diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2001-01-10 05:27:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2001-01-10 05:27:25 +0000 |
commit | c9c06167e7933d93a6e396174c68abf242294abb (patch) | |
tree | d9a8bb30663e9a3405a1ef37ffb62bc14b9f019f /drivers/video | |
parent | f79e8cc3c34e4192a3e5ef4cc9c6542fdef703c0 (diff) |
Merge with Linux 2.4.0-test12.
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/amifb.c | 90 | ||||
-rw-r--r-- | drivers/video/atafb.c | 17 | ||||
-rw-r--r-- | drivers/video/aty128fb.c | 21 | ||||
-rw-r--r-- | drivers/video/atyfb.c | 19 | ||||
-rw-r--r-- | drivers/video/dummycon.c | 3 | ||||
-rw-r--r-- | drivers/video/fbcon-sti.c | 330 | ||||
-rw-r--r-- | drivers/video/fbmem.c | 5 | ||||
-rw-r--r-- | drivers/video/macmodes.c | 2 | ||||
-rw-r--r-- | drivers/video/mdacon.c | 18 | ||||
-rw-r--r-- | drivers/video/platinumfb.c | 24 | ||||
-rw-r--r-- | drivers/video/sti-bmode.h | 287 | ||||
-rw-r--r-- | drivers/video/sti.h | 289 | ||||
-rw-r--r-- | drivers/video/sticon-bmode.c | 906 | ||||
-rw-r--r-- | drivers/video/sticon.c | 229 | ||||
-rw-r--r-- | drivers/video/sticore.c | 598 | ||||
-rw-r--r-- | drivers/video/stifb.c | 230 | ||||
-rw-r--r-- | drivers/video/tdfxfb.c | 42 | ||||
-rw-r--r-- | drivers/video/vgacon.c | 2 |
19 files changed, 2973 insertions, 141 deletions
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 96de87f86..54dd6eca1 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -68,7 +68,7 @@ obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o -obj-$(CONFIG_FB_MAC) += macfb.o +obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o obj-$(CONFIG_FB_HP300) += hpfb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_IMSTT) += imsttfb.o diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index e6ad28fcf..44f6fc8c5 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -750,13 +750,6 @@ static struct fb_info fb_info; /* - * The minimum period for audio depends on htotal (for OCS/ECS/AGA) - * (Imported from arch/m68k/amiga/amisound.c) - */ - -extern volatile u_short amiga_audio_min_period; - - /* * Since we can't read the palette on OCS/ECS, and since reading one * single color palette entry requires 5 expensive custom chip bus accesses * on AGA, we keep a copy of the current palette. @@ -1206,6 +1199,8 @@ int __init amifb_setup(char *options) if (!strcmp(this_opt, "inverse")) { amifb_inverse = 1; fb_invert_cmaps(); + } else if (!strcmp(this_opt, "off")) { + amifb_video_off(); } else if (!strcmp(this_opt, "ilbm")) amifb_ilbm = 1; else if (!strncmp(this_opt, "monitorcap:", 11)) @@ -1771,7 +1766,7 @@ default_chipset: * access the videomem with writethrough cache */ videomemory_phys = (u_long)ZTWO_PADDR(videomemory); - videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize); + //videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize); if (!videomemory) { printk("amifb: WARNING! unable to map videomem cached writethrough\n"); videomemory = ZTWO_VADDR(videomemory_phys); @@ -1792,15 +1787,11 @@ default_chipset: ami_init_copper(); - if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, 0, - "fb vertb handler", NULL)) { + if (request_irq(IRQ_AMIGA_VERTB, amifb_interrupt, 0, + "fb vertb handler", ¤tpar)) { err = -EBUSY; goto amifb_error; } - amiga_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER; - amiga_intena_vals[IRQ_AMIGA_COPPER] = 0; - custom.intena = IF_VERTB; - custom.intena = IF_SETCLR | IF_COPER; amifb_set_var(&var, -1, &fb_info); @@ -1895,57 +1886,33 @@ static int flash_cursor(void) static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp) { - u_short ints = custom.intreqr & custom.intenar; - static struct irq_server server = {0, 0}; - unsigned long flags; - - if (ints & IF_BLIT) { - custom.intreq = IF_BLIT; - amiga_do_irq(IRQ_AMIGA_BLIT, fp); - } - - if (ints & IF_COPER) { - custom.intreq = IF_COPER; - if (do_vmode_pan || do_vmode_full) - ami_update_display(); - - if (do_vmode_full) - ami_init_display(); - - if (do_vmode_pan) { - flash_cursor(); - ami_rebuild_copper(); - do_cursor = do_vmode_pan = 0; - } else if (do_cursor) { - flash_cursor(); + if (do_vmode_pan || do_vmode_full) + ami_update_display(); + + if (do_vmode_full) + ami_init_display(); + + if (do_vmode_pan) { + flash_cursor(); + ami_rebuild_copper(); + do_cursor = do_vmode_pan = 0; + } else if (do_cursor) { + flash_cursor(); + ami_set_sprite(); + do_cursor = 0; + } else { + if (flash_cursor()) ami_set_sprite(); - do_cursor = 0; - } else { - if (flash_cursor()) - ami_set_sprite(); - } - - save_flags(flags); - cli(); - if (get_vbpos() < down2(currentpar.diwstrt_v - 6)) - custom.copjmp2 = 0; - restore_flags(flags); - - if (do_blank) { - ami_do_blank(); - do_blank = 0; - } + } - if (do_vmode_full) { - ami_reinit_copper(); - do_vmode_full = 0; - } - amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server); + if (do_blank) { + ami_do_blank(); + do_blank = 0; } - if (ints & IF_VERTB) { - printk("%s: Warning: IF_VERTB was enabled\n", __FUNCTION__); - custom.intena = IF_VERTB; + if (do_vmode_full) { + ami_reinit_copper(); + do_vmode_full = 0; } } @@ -3379,5 +3346,6 @@ void cleanup_module(void) { unregister_framebuffer(&fb_info); amifb_deinit(); + amifb_video_off(); } #endif /* MODULE */ diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index c09a691a8..e305027a7 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -2425,6 +2425,21 @@ do_install_cmap(int con, struct fb_info *info) } static int +atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) +{ + struct atafb_par par; + if (con == -1) + atafb_get_par(&par); + else { + int err; + if ((err=fbhw->decode_var(&fb_display[con].var,&par))) + return err; + } + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + return fbhw->encode_fix(fix, &par); +} + +static int atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { struct atafb_par par; @@ -2776,7 +2791,7 @@ int __init atafb_init(void) #endif /* ATAFB_EXT */ mem_req = default_mem_req + ovsc_offset + ovsc_addlen; mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE; - screen_base = atari_stram_alloc(mem_req, NULL, "atafb"); + screen_base = atari_stram_alloc(mem_req, "atafb"); if (!screen_base) panic("Cannot allocate screen memory"); memset(screen_base, 0, mem_req); diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index 05fcfcbe1..626bf3cad 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -283,7 +283,6 @@ struct fb_info_aty128 { const struct aty128_meminfo *mem; /* onboard mem info */ struct aty128fb_par default_par, current_par; struct display disp; - struct display_switch dispsw; /* for cursor and font */ struct { u8 red, green, blue, pad; } palette[256]; union { #ifdef FBCON_HAS_CFB16 @@ -347,7 +346,7 @@ static void aty128fbcon_blank(int blank, struct fb_info *fb); static void aty128_encode_fix(struct fb_fix_screeninfo *fix, struct aty128fb_par *par, const struct fb_info_aty128 *info); -static void aty128_set_disp(struct display *disp, +static void aty128_set_dispsw(struct display *disp, struct fb_info_aty128 *info, int bpp, int accel); static int aty128_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info); @@ -1392,7 +1391,7 @@ aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb) display->inverse = 0; accel = var->accel_flags & FB_ACCELF_TEXT; - aty128_set_disp(display, info, par.crtc.bpp, accel); + aty128_set_dispsw(display, info, par.crtc.bpp, accel); if (accel) display->scrollmode = SCROLL_YNOMOVE; @@ -1417,35 +1416,31 @@ aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb) static void -aty128_set_disp(struct display *disp, +aty128_set_dispsw(struct display *disp, struct fb_info_aty128 *info, int bpp, int accel) { switch (bpp) { #ifdef FBCON_HAS_CFB8 case 8: - info->dispsw = accel ? fbcon_aty128_8 : fbcon_cfb8; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8; break; #endif #ifdef FBCON_HAS_CFB16 case 15: case 16: - info->dispsw = accel ? fbcon_aty128_16 : fbcon_cfb16; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16; disp->dispsw_data = info->fbcon_cmap.cfb16; break; #endif #ifdef FBCON_HAS_CFB24 case 24: - info->dispsw = accel ? fbcon_aty128_24 : fbcon_cfb24; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24; disp->dispsw_data = info->fbcon_cmap.cfb24; break; #endif #ifdef FBCON_HAS_CFB32 case 32: - info->dispsw = accel ? fbcon_aty128_32 : fbcon_cfb32; - disp->dispsw = &info->dispsw; + disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32; disp->dispsw_data = info->fbcon_cmap.cfb32; break; #endif @@ -2135,7 +2130,7 @@ aty128fbcon_switch(int con, struct fb_info *fb) aty128_decode_var(&fb_display[con].var, &par, info); aty128_set_par(&par, info); - aty128_set_disp(&fb_display[con], info, par.crtc.bpp, + aty128_set_dispsw(&fb_display[con], info, par.crtc.bpp, par.accel_flags & FB_ACCELF_TEXT); do_install_cmap(con, fb); diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 48b3b4ca2..fb3b09bc9 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -466,8 +466,8 @@ static void set_off_pitch(struct atyfb_par *par, static int encode_fix(struct fb_fix_screeninfo *fix, const struct atyfb_par *par, const struct fb_info_aty *info); -static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info, - int bpp, int accel); +static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, + int bpp, int accel); static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *fb); static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, @@ -2826,8 +2826,8 @@ static int atyfb_get_var(struct fb_var_screeninfo *var, int con, } -static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info, - int bpp, int accel) +static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, + int bpp, int accel) { switch (bpp) { #ifdef FBCON_HAS_CFB8 @@ -2898,6 +2898,7 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, oldbpp = display->var.bits_per_pixel; oldaccel = display->var.accel_flags; display->var = *var; + accel = var->accel_flags & FB_ACCELF_TEXT; if (oldxres != var->xres || oldyres != var->yres || oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { @@ -2913,8 +2914,6 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, display->line_length = fix.line_length; display->can_soft_blank = 1; display->inverse = 0; - accel = var->accel_flags & FB_ACCELF_TEXT; - atyfb_set_disp(display, info, par.crtc.bpp, accel); if (accel) display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0; else @@ -2923,8 +2922,10 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, (*info->fb_info.changevar)(con); } if (!info->fb_info.display_fg || - info->fb_info.display_fg->vc_num == con) + info->fb_info.display_fg->vc_num == con) { atyfb_set_par(&par, info); + atyfb_set_dispsw(display, info, par.crtc.bpp, accel); + } if (oldbpp != var->bits_per_pixel) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; @@ -4241,8 +4242,8 @@ static int atyfbcon_switch(int con, struct fb_info *fb) atyfb_decode_var(&fb_display[con].var, &par, info); atyfb_set_par(&par, info); - atyfb_set_disp(&fb_display[con], info, par.crtc.bpp, - par.accel_flags & FB_ACCELF_TEXT); + atyfb_set_dispsw(&fb_display[con], info, par.crtc.bpp, + par.accel_flags & FB_ACCELF_TEXT); /* Install new colormap */ do_install_cmap(con, fb); diff --git a/drivers/video/dummycon.c b/drivers/video/dummycon.c index 3e08ebcb2..f7a09a5d0 100644 --- a/drivers/video/dummycon.c +++ b/drivers/video/dummycon.c @@ -20,6 +20,9 @@ #if defined(__arm__) #define DUMMY_COLUMNS ORIG_VIDEO_COLS #define DUMMY_ROWS ORIG_VIDEO_LINES +#elif defined(__hppa__) +#define DUMMY_COLUMNS 80 /* fixme ! (mine uses 160x64 at 1280x1024) */ +#define DUMMY_ROWS 25 #else #define DUMMY_COLUMNS 80 #define DUMMY_ROWS 25 diff --git a/drivers/video/fbcon-sti.c b/drivers/video/fbcon-sti.c new file mode 100644 index 000000000..174ad05c4 --- /dev/null +++ b/drivers/video/fbcon-sti.c @@ -0,0 +1,330 @@ +/* + * linux/drivers/video/fbcon-sti.c -- Low level frame buffer + * operations for generic HP video boards using STI (standard + * text interface) firmware + * + * Based on linux/drivers/video/fbcon-artist.c + * Created 5 Apr 1997 by Geert Uytterhoeven + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. */ + +#include <linux/module.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <asm/delay.h> +#include <asm/types.h> + +#include <video/fbcon.h> +#include <video/fbcon-mfb.h> + +#include "sti.h" + +/* Translate an address as it would be found in a 2048x2048x1 bit frame + * buffer into a logical address Artist actually expects. Addresses fed + * into Artist look like this: + * fixed Y X + * FFFF FFFF LLLL LLLL LLLC CCCC CCCC CC00 + * + * our "RAM" addresses look like this: + * + * FFFF FFFF 0000 0LLL LLLL LLLL CCCC CCCC [CCC] + * + * */ + +static inline u32 +ram2log(void * addr) +{ + u32 a = (unsigned long) addr; + u32 r; + +#if 0 + r = a & 0xff000000; /* fixed part */ + r += ((a & 0x000000ff) << 5); + r += ((a & 0x00ffff00) << 3); +#else + r = a & 0xff000000; /* fixed part */ + r += ((a & 0x000000ff) << 5); + r += ((a & 0x0007ff00) << 5); +#endif + + return r; +} + +/* All those functions need better names. */ + +static void +memcpy_fromhp_tohp(void *dest, void *src, int count) +{ + unsigned long d = ram2log(dest); + unsigned long s = ram2log(src); + + count += 3; + count &= ~3; /* XXX */ + + while(count) { + count --; + gsc_writel(~gsc_readl(s), d); + d += 32*4; + s += 32*4; + } +} + +static void +memcpy_tohp(void *dest, void *src, int count) +{ + unsigned long d = (unsigned long) dest; + u32 *s = (u32 *)src; + + count += 3; + count &= ~3; /* XXX */ + + d = ram2log(dest); + + while(count) { + count--; + gsc_writel(*s++, d); + d += 32*4; + } +} + +static void +memcopy_fromhp(void *dest, void *src, int count) +{ + /* FIXME */ + printk("uhm ...\n"); +} + +static void +memset_tohp(void *dest, u32 word, int count) +{ + unsigned long d = ram2log(dest); + + count += 3; + count &= ~3; + + while(count) { + count--; + gsc_writel(word, d); + d += 32; + } +} + +static u8 +readb_hp(void *src) +{ + unsigned long s = ram2log(src); + + return ~gsc_readb(s); +} + +static void +writeb_hp(u8 b, void *dst) +{ + unsigned long d = ram2log(dst); + + if((d&0xf0000000) != 0xf0000000) { + printk("writeb_hp %02x %p (%08lx) (%p)\n", + b, dst, d, __builtin_return_address(0)); + return; + } + + gsc_writeb(b, d); +} + +static void +fbcon_sti_setup(struct display *p) +{ + if (p->line_length) + p->next_line = p->line_length; + else + p->next_line = p->var.xres_virtual>>3; + p->next_plane = 0; +} + +static void +fbcon_sti_bmove(struct display *p, int sy, int sx, + int dy, int dx, + int height, int width) +{ +#if 0 /* Unfortunately, still broken */ + sti_bmove(&default_sti /* FIXME */, sy, sx, dy, dx, height, width); +#else + u8 *src, *dest; + u_int rows; + + if (sx == 0 && dx == 0 && width == p->next_line) { + src = p->screen_base+sy*fontheight(p)*width; + dest = p->screen_base+dy*fontheight(p)*width; + memcpy_fromhp_tohp(dest, src, height*fontheight(p)*width); + } else if (dy <= sy) { + src = p->screen_base+sy*fontheight(p)*p->next_line+sx; + dest = p->screen_base+dy*fontheight(p)*p->next_line+dx; + for (rows = height*fontheight(p); rows--;) { + memcpy_fromhp_tohp(dest, src, width); + src += p->next_line; + dest += p->next_line; + } + } else { + src = p->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx; + dest = p->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx; + for (rows = height*fontheight(p); rows--;) { + memcpy_fromhp_tohp(dest, src, width); + src -= p->next_line; + dest -= p->next_line; + } + } +#endif +} + +static void +fbcon_sti_clear(struct vc_data *conp, + struct display *p, int sy, int sx, + int height, int width) +{ + u8 *dest; + u_int rows; + int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0; + + dest = p->screen_base+sy*fontheight(p)*p->next_line+sx; + + if (sx == 0 && width == p->next_line) { + if (inverse) + memset_tohp(dest, ~0, height*fontheight(p)*width); + else + memset_tohp(dest, 0, height*fontheight(p)*width); + } else + for (rows = height*fontheight(p); rows--; dest += p->next_line) + if (inverse) + memset_tohp(dest, 0xffffffff, width); + else + memset_tohp(dest, 0x00000000, width); +} + +static void fbcon_sti_putc(struct vc_data *conp, + struct display *p, int c, + int yy, int xx) +{ + u8 *dest, *cdat; + u_int rows, bold, revs, underl; + u8 d; + + dest = p->screen_base+yy*fontheight(p)*p->next_line+xx; + cdat = p->fontdata+(c&p->charmask)*fontheight(p); + bold = attr_bold(p,c); + revs = attr_reverse(p,c); + underl = attr_underline(p,c); + + for (rows = fontheight(p); rows--; dest += p->next_line) { + d = *cdat++; + if (underl && !rows) + d = 0xff; + else if (bold) + d |= d>>1; + if (revs) + d = ~d; + writeb_hp (d, dest); + } +} + +static void fbcon_sti_putcs(struct vc_data *conp, + struct display *p, + const unsigned short *s, + int count, int yy, int xx) +{ + u8 *dest, *dest0, *cdat; + u_int rows, bold, revs, underl; + u8 d; + u16 c; + + if(((unsigned)xx > 200) || ((unsigned) yy > 200)) { + printk("refusing to putcs %p %p %p %d %d %d (%p)\n", + conp, p, s, count, yy, xx, __builtin_return_address(0)); + return; + } + + + dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx; + if(((u32)dest0&0xf0000000)!=0xf0000000) { + printk("refusing to putcs %p %p %p %d %d %d (%p) %p = %p + %d * %d * %ld + %d\n", + conp, p, s, count, yy, xx, __builtin_return_address(0), + dest0, p->screen_base, yy, fontheight(p), p->next_line, + xx); + return; + } + + bold = attr_bold(p,scr_readw(s)); + revs = attr_reverse(p,scr_readw(s)); + underl = attr_underline(p,scr_readw(s)); + + while (count--) { + c = scr_readw(s++) & p->charmask; + dest = dest0++; + cdat = p->fontdata+c*fontheight(p); + for (rows = fontheight(p); rows--; dest += p->next_line) { + d = *cdat++; + if (0 && underl && !rows) + d = 0xff; + else if (0 && bold) + d |= d>>1; + if (revs) + d = ~d; + writeb_hp (d, dest); + } + } +} + +static void fbcon_sti_revc(struct display *p, + int xx, int yy) +{ + u8 *dest, d; + u_int rows; + + + dest = p->screen_base+yy*fontheight(p)*p->next_line+xx; + for (rows = fontheight(p); rows--; dest += p->next_line) { + d = readb_hp(dest); + writeb_hp (~d, dest); + } +} + +static void +fbcon_sti_clear_margins(struct vc_data *conp, + struct display *p, + int bottom_only) +{ + u8 *dest; + int height, bottom; + int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0; + + + /* XXX Need to handle right margin? */ + + height = p->var.yres - conp->vc_rows * fontheight(p); + if (!height) + return; + bottom = conp->vc_rows + p->yscroll; + if (bottom >= p->vrows) + bottom -= p->vrows; + dest = p->screen_base + bottom * fontheight(p) * p->next_line; + if (inverse) + memset_tohp(dest, 0xffffffff, height * p->next_line); + else + memset_tohp(dest, 0x00000000, height * p->next_line); +} + + + /* + * `switch' for the low level operations + */ + +struct display_switch fbcon_sti = { + fbcon_sti_setup, fbcon_sti_bmove, fbcon_sti_clear, + fbcon_sti_putc, fbcon_sti_putcs, fbcon_sti_revc, + NULL, NULL, fbcon_sti_clear_margins, + FONTWIDTH(8) +}; diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ba6d70289..60b76a447 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -113,6 +113,8 @@ extern int tdfxfb_init(void); extern int tdfxfb_setup(char*); extern int sisfb_init(void); extern int sisfb_setup(char*); +extern int stifb_init(void); +extern int stifb_setup(char*); extern int pmagbafb_init(void); extern int pmagbafb_setup(char *); @@ -200,6 +202,9 @@ static struct { * management! */ +#ifdef CONFIG_FB_STI + { "stifb", stifb_init, stifb_setup }, +#endif #ifdef CONFIG_FB_OF { "offb", offb_init, NULL }, #endif diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c index 8f984ae12..d1ff9c8cc 100644 --- a/drivers/video/macmodes.c +++ b/drivers/video/macmodes.c @@ -17,7 +17,9 @@ #include <linux/fb.h> #include <linux/string.h> +#ifdef CONFIG_FB_COMPAT_XPMAC #include <asm/vc_ioctl.h> +#endif #include <video/fbcon.h> #include <video/macmodes.h> diff --git a/drivers/video/mdacon.c b/drivers/video/mdacon.c index d988d9e39..98e58b46c 100644 --- a/drivers/video/mdacon.c +++ b/drivers/video/mdacon.c @@ -77,10 +77,8 @@ static int mda_last_vc = 16; static struct vc_data *mda_display_fg = NULL; -#ifdef MODULE_PARM MODULE_PARM(mda_first_vc, "1-255i"); MODULE_PARM(mda_last_vc, "1-255i"); -#endif /* MDA register values */ @@ -200,11 +198,7 @@ void __init mdacon_setup(char *str, int *ints) } #endif -#ifdef MODULE -static int mda_detect(void) -#else static int __init mda_detect(void) -#endif { int count=0; u16 *p, p_save; @@ -287,11 +281,7 @@ static int __init mda_detect(void) return 1; } -#ifdef MODULE -static void mda_initialize(void) -#else static void __init mda_initialize(void) -#endif { write_mda_b(97, 0x00); /* horizontal total */ write_mda_b(80, 0x01); /* horizontal displayed */ @@ -316,11 +306,7 @@ static void __init mda_initialize(void) outb_p(0x00, mda_gfx_port); } -#ifdef MODULE -static const char *mdacon_startup(void) -#else static const char __init *mdacon_startup(void) -#endif { mda_num_columns = 80; mda_num_lines = 25; @@ -605,11 +591,7 @@ const struct consw mda_con = { con_invert_region: mdacon_invert_region, }; -#ifdef MODULE -void mda_console_init(void) -#else void __init mda_console_init(void) -#endif { if (mda_first_vc > mda_last_vc) return; diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 558b6f44e..20ab5c4e5 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -65,7 +65,6 @@ struct fb_par_platinum { struct fb_info_platinum { struct fb_info fb_info; struct display disp; - struct display_switch dispsw; struct fb_par_platinum default_par; struct fb_par_platinum current_par; @@ -140,8 +139,9 @@ static int platinum_var_to_par(const struct fb_var_screeninfo *var, static int platinum_encode_fix(struct fb_fix_screeninfo *fix, const struct fb_par_platinum *par, const struct fb_info_platinum *info); -static void platinum_set_disp(struct display *disp, struct fb_info_platinum *info, - int cmode, int accel); +static void platinum_set_dispsw(struct display *disp, + struct fb_info_platinum *info, int cmode, + int accel); static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *fb); static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue, @@ -193,27 +193,25 @@ static int platinum_get_var(struct fb_var_screeninfo *var, int con, return 0; } -static void platinum_set_disp(struct display *disp, struct fb_info_platinum *info, - int cmode, int accel) +static void platinum_set_dispsw(struct display *disp, + struct fb_info_platinum *info, int cmode, + int accel) { switch(cmode) { #ifdef FBCON_HAS_CFB8 case CMODE_8: - info->dispsw = fbcon_cfb8; - disp->dispsw = &info->dispsw; + disp->dispsw = &fbcon_cfb8; break; #endif #ifdef FBCON_HAS_CFB16 case CMODE_16: - info->dispsw = fbcon_cfb16; - disp->dispsw = &info->dispsw; + disp->dispsw = &fbcon_cfb16; disp->dispsw_data = info->fbcon_cmap.cfb16; break; #endif #ifdef FBCON_HAS_CFB32 case CMODE_32: - info->dispsw = fbcon_cfb32; - disp->dispsw = &info->dispsw; + disp->dispsw = &fbcon_cfb32; disp->dispsw_data = info->fbcon_cmap.cfb32; break; #endif @@ -271,7 +269,7 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con, display->line_length = fix.line_length; display->can_soft_blank = 1; display->inverse = 0; - platinum_set_disp(display, info, par.cmode, 0); + platinum_set_dispsw(display, info, par.cmode, 0); display->scrollmode = SCROLL_YREDRAW; if (info->fb_info.changevar) (*info->fb_info.changevar)(con); @@ -341,7 +339,7 @@ static int platinum_switch(int con, struct fb_info *fb) platinum_var_to_par(&fb_display[con].var, &par, info); platinum_set_par(&par, info); - platinum_set_disp(&fb_display[con], info, par.cmode, 0); + platinum_set_dispsw(&fb_display[con], info, par.cmode, 0); do_install_cmap(con, fb); return 1; diff --git a/drivers/video/sti-bmode.h b/drivers/video/sti-bmode.h new file mode 100644 index 000000000..4aa38f6d9 --- /dev/null +++ b/drivers/video/sti-bmode.h @@ -0,0 +1,287 @@ +#define STI_REGION_MAX 8 +#define STI_DEV_NAME_LENGTH 32 + +typedef struct { + u8 res[3]; + u8 data; +} __attribute__((packed)) sti_u8; + +typedef struct { + sti_u8 data[2]; +} __attribute__((packed)) sti_u16; + +typedef struct { + sti_u8 data[4]; +} __attribute__((packed)) sti_u32; + +#define STI_U8( u8) ((u8).data) +#define STI_U16(u16) ((STI_U8((u16).data[0])<<8) | STI_U8((u16).data[1])) +#define STI_U32(u32) ((STI_U8((u32).data[0])<<24) | \ + (STI_U8((u32).data[1])<<16) | \ + (STI_U8((u32).data[2])<< 8) | \ + (STI_U8((u32).data[3])<< 0)) + +struct sti_rom_region { + sti_u32 region; +}; + +struct sti_rom_font { + sti_u16 first_char; + sti_u16 last_char; + sti_u8 width; + sti_u8 height; + sti_u8 font_type; + sti_u8 bytes_per_char; + sti_u32 next_font; + sti_u8 underline_height; + sti_u8 underline_pos; + sti_u8 res008[2]; +}; + +struct sti_rom { + sti_u8 type; + sti_u8 num_mons; + sti_u8 revno[2]; + + sti_u8 graphics_id[8]; /* 0x010 */ + + sti_u32 font_start; /* 0x030 */ + sti_u32 statesize; + sti_u32 last_addr; + sti_u32 region_list; + + sti_u16 reentsize; /* 0x070 */ + sti_u16 maxtime; + sti_u32 mon_tbl_addr; + sti_u32 user_data_addr; + sti_u32 sti_mem_req; + + sti_u32 user_data_size; /* 0x0b0 */ + sti_u16 power; /* 0x0c0 */ + sti_u8 bus_support; + sti_u8 ext_bus_support; + sti_u8 alt_code_type; /* 0x0d0 */ + sti_u8 ext_dd_struct[3]; + sti_u32 cfb_addr; /* 0x0e0 */ + + sti_u8 res0f0[4]; + + sti_u32 init_graph; /* 0x0e0 */ + sti_u32 state_mgmt; + sti_u32 font_unpmv; + sti_u32 block_move; + sti_u32 self_test; + sti_u32 excep_hdlr; + sti_u32 inq_conf; + sti_u32 set_cm_entry; + sti_u32 dma_ctrl; + sti_u32 flow_ctrl; + sti_u32 user_timing; + sti_u32 process_mgr; + sti_u32 sti_util; + sti_u32 end_addr; + sti_u32 res0b8; + sti_u32 res0bc; + + sti_u32 init_graph_m68k; /* 0x0e0 */ + sti_u32 state_mgmt_m68k; + sti_u32 font_unpmv_m68k; + sti_u32 block_move_m68k; + sti_u32 self_test_m68k; + sti_u32 excep_hdlr_m68k; + sti_u32 inq_conf_m68k; + sti_u32 set_cm_entry_m68k; + sti_u32 dma_ctrl_m68k; + sti_u32 flow_ctrl_m68k; + sti_u32 user_timing_m68k; + sti_u32 process_mgr_m68k; + sti_u32 sti_util_m68k; + sti_u32 end_addr_m68k; + sti_u32 res0b8_m68k; + sti_u32 res0bc_m68k; + + sti_u8 res040[7 * 4]; +}; + +struct sti_cooked_font { + struct sti_rom_font *raw; + struct sti_cooked_font *next_font; +}; + +struct sti_cooked_rom { + struct sti_rom *raw; + struct sti_cooked_font *font_start; + u32 *region_list; +}; + +struct sti_glob_cfg_ext { + u8 curr_mon; + u8 friendly_boot; + s16 power; + s32 freq_ref; + s32 *sti_mem_addr; + s32 *future_ptr; +}; + +struct sti_glob_cfg { + s32 text_planes; + s16 onscreen_x; + s16 onscreen_y; + s16 offscreen_x; + s16 offscreen_y; + s16 total_x; + s16 total_y; + u32 region_ptrs[STI_REGION_MAX]; + s32 reent_lvl; + s32 *save_addr; + struct sti_glob_cfg_ext *ext_ptr; +}; + +struct sti_init_flags { + u32 wait : 1; + u32 reset : 1; + u32 text : 1; + u32 nontext : 1; + u32 clear : 1; + u32 cmap_blk : 1; + u32 enable_be_timer : 1; + u32 enable_be_int : 1; + u32 no_chg_tx : 1; + u32 no_chg_ntx : 1; + u32 no_chg_bet : 1; + u32 no_chg_bei : 1; + u32 init_cmap_tx : 1; + u32 cmt_chg : 1; + u32 retain_ie : 1; + u32 pad : 17; + + s32 *future_ptr; +}; + +struct sti_init_inptr_ext { + u8 config_mon_type; + u8 pad[1]; + u16 inflight_data; + s32 *future_ptr; +}; + +struct sti_init_inptr { + s32 text_planes; + struct sti_init_inptr_ext *ext_ptr; +}; + +struct sti_init_outptr { + s32 errno; + s32 text_planes; + s32 *future_ptr; +}; + +struct sti_conf_flags { + u32 wait : 1; + u32 pad : 31; + s32 *future_ptr; +}; + +struct sti_conf_inptr { + s32 *future_ptr; +}; + +struct sti_conf_outptr_ext { + u32 crt_config[3]; + u32 crt_hdw[3]; + s32 *future_ptr; +}; + +struct sti_conf_outptr { + s32 errno; + s16 onscreen_x; + s16 onscreen_y; + s16 offscreen_x; + s16 offscreen_y; + s16 total_x; + s16 total_y; + s32 bits_per_pixel; + s32 bits_used; + s32 planes; + u8 dev_name[STI_DEV_NAME_LENGTH]; + u32 attributes; + struct sti_conf_outptr_ext *ext_ptr; +}; + + +struct sti_font_inptr { + u32 font_start_addr; + s16 index; + u8 fg_color; + u8 bg_color; + s16 dest_x; + s16 dest_y; + s32 *future_ptr; +}; + +struct sti_font_flags { + u32 wait : 1; + u32 non_text : 1; + u32 pad : 30; + + s32 *future_ptr; +}; + +struct sti_font_outptr { + s32 errno; + s32 *future_ptr; +}; + +struct sti_blkmv_flags { + u32 wait : 1; + u32 color : 1; + u32 clear : 1; + u32 non_text : 1; + u32 pad : 28; + s32 *future_ptr; +}; + +struct sti_blkmv_inptr { + u8 fg_color; + u8 bg_color; + s16 src_x; + s16 src_y; + s16 dest_x; + s16 dest_y; + s16 width; + s16 height; + s32 *future_ptr; +}; + +struct sti_blkmv_outptr { + s32 errno; + s32 *future_ptr; +}; + +struct sti_struct { + spinlock_t lock; + + struct sti_cooked_rom *rom; + + unsigned long font_unpmv; + unsigned long block_move; + unsigned long init_graph; + unsigned long inq_conf; + + struct sti_glob_cfg *glob_cfg; + struct sti_rom_font *font; + + s32 text_planes; + + char **mon_strings; + u32 *regions; + u8 *pci_regions; +}; + +#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \ + ({ \ + real32_call( func, (unsigned long)STI_PTR(flags), \ + STI_PTR(inptr), STI_PTR(outptr), \ + glob_cfg); \ + }) + diff --git a/drivers/video/sti.h b/drivers/video/sti.h new file mode 100644 index 000000000..feea4fb92 --- /dev/null +++ b/drivers/video/sti.h @@ -0,0 +1,289 @@ +#define STI_REGION_MAX 8 +#define STI_DEV_NAME_LENGTH 32 + +struct sti_rom_font { + u16 first_char; + u16 last_char; + u8 width; + u8 height; + u8 font_type; + u8 bytes_per_char; + u32 next_font; + u8 underline_height; + u8 underline_pos; + u8 res008[2]; +}; + +struct sti_rom { + u8 type[4]; + u8 res004; + u8 num_mons; + u8 revno[2]; + u8 graphics_id[8]; + + u32 font_start; + u32 statesize; + u32 last_addr; + u32 region_list; + + u16 reentsize; + u16 maxtime; + u32 mon_tbl_addr; + u32 user_data_addr; + u32 sti_mem_req; + + u32 user_data_size; + u16 power; + u8 bus_support; + u8 ext_bus_support; + u8 alt_code_type; + u8 ext_dd_struct[3]; + u32 cfb_addr; + + u32 init_graph; + u32 state_mgmt; + u32 font_unpmv; + u32 block_move; + u32 self_test; + u32 excep_hdlr; + u32 inq_conf; + u32 set_cm_entry; + u32 dma_ctrl; + u8 res040[7 * 4]; + + u32 init_graph_m68k; + u32 flow_ctrl; + u32 user_timing; + u32 process_mgr; + u32 sti_util; + u32 end_addr; + u32 res0b8; + u32 res0bc; +}; + +struct sti_cooked_font { + struct sti_rom_font *raw; + struct sti_cooked_font *next_font; +}; + +struct sti_cooked_rom { + struct sti_rom *raw; + struct sti_cooked_font *font_start; + u32 *region_list; +}; + +struct sti_glob_cfg_ext { + u8 curr_mon; + u8 friendly_boot; + s16 power; + s32 freq_ref; + s32 *sti_mem_addr; + s32 *future_ptr; +}; + +struct sti_glob_cfg { + s32 text_planes; + s16 onscreen_x; + s16 onscreen_y; + s16 offscreen_x; + s16 offscreen_y; + s16 total_x; + s16 total_y; + u32 region_ptrs[STI_REGION_MAX]; + s32 reent_lvl; + s32 *save_addr; + struct sti_glob_cfg_ext *ext_ptr; +}; + +struct sti_init_flags { + u32 wait : 1; + u32 reset : 1; + u32 text : 1; + u32 nontext : 1; + u32 clear : 1; + u32 cmap_blk : 1; + u32 enable_be_timer : 1; + u32 enable_be_int : 1; + u32 no_chg_tx : 1; + u32 no_chg_ntx : 1; + u32 no_chg_bet : 1; + u32 no_chg_bei : 1; + u32 init_cmap_tx : 1; + u32 cmt_chg : 1; + u32 retain_ie : 1; + u32 pad : 17; + + s32 *future_ptr; +}; + +struct sti_init_inptr_ext { + u8 config_mon_type; + u8 pad[1]; + u16 inflight_data; + s32 *future_ptr; +}; + +struct sti_init_inptr { + s32 text_planes; + struct sti_init_inptr_ext *ext_ptr; +}; + +struct sti_init_outptr { + s32 errno; + s32 text_planes; + s32 *future_ptr; +}; + +struct sti_conf_flags { + u32 wait : 1; + u32 pad : 31; + s32 *future_ptr; +}; + +struct sti_conf_inptr { + s32 *future_ptr; +}; + +struct sti_conf_outptr_ext { + u32 crt_config[3]; + u32 crt_hdw[3]; + s32 *future_ptr; +}; + +struct sti_conf_outptr { + s32 errno; + s16 onscreen_x; + s16 onscreen_y; + s16 offscreen_x; + s16 offscreen_y; + s16 total_x; + s16 total_y; + s32 bits_per_pixel; + s32 bits_used; + s32 planes; + u8 dev_name[STI_DEV_NAME_LENGTH]; + u32 attributes; + struct sti_conf_outptr_ext *ext_ptr; +}; + + +struct sti_font_inptr { + u32 font_start_addr; + s16 index; + u8 fg_color; + u8 bg_color; + s16 dest_x; + s16 dest_y; + s32 *future_ptr; +}; + +struct sti_font_flags { + u32 wait : 1; + u32 non_text : 1; + u32 pad : 30; + + s32 *future_ptr; +}; + +struct sti_font_outptr { + s32 errno; + s32 *future_ptr; +}; + +struct sti_blkmv_flags { + u32 wait : 1; + u32 color : 1; + u32 clear : 1; + u32 non_text : 1; + u32 pad : 28; + s32 *future_ptr; +}; + +struct sti_blkmv_inptr { + u8 fg_color; + u8 bg_color; + s16 src_x; + s16 src_y; + s16 dest_x; + s16 dest_y; + s16 width; + s16 height; + s32 *future_ptr; +}; + +struct sti_blkmv_outptr { + s32 errno; + s32 *future_ptr; +}; + +struct sti_struct { + spinlock_t lock; + + struct sti_cooked_rom *rom; + + unsigned long font_unpmv; + unsigned long block_move; + unsigned long init_graph; + unsigned long inq_conf; + + struct sti_glob_cfg *glob_cfg; + struct sti_rom_font *font; + + s32 text_planes; + + char **mon_strings; + u32 *regions; + u8 *pci_regions; +}; + +#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \ + ({ \ + real32_call( func, (unsigned long)STI_PTR(flags), \ + STI_PTR(inptr), STI_PTR(outptr), \ + glob_cfg); \ + }) + +/* The latency of the STI functions cannot really be reduced by setting + * this to 0; STI doesn't seem to be designed to allow calling a different + * function (or the same function with different arguments) after a + * function exited with 1 as return value. + * + * As all of the functions below could be called from interrupt context, + * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1) + * block. Really bad latency there. + * + * Probably the best solution to all this is have the generic code manage + * the screen buffer and a kernel thread to call STI occasionally. + * + * Luckily, the frame buffer guys have the same problem so we can just wait + * for them to fix it and steal their solution. prumpf + * + * Actually, another long-term viable solution is to completely do STI + * support in userspace - that way we avoid the potential license issues + * of using proprietary fonts, too. */ + +#define STI_WAIT 1 +#define STI_PTR(p) ( (typeof(p)) virt_to_phys(p)) +#define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) ) + +#define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x) +#define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y) +#define sti_font_x(sti) (PTR_STI(sti->font)->width) +#define sti_font_y(sti) (PTR_STI(sti->font)->height) + +extern struct sti_struct * sti_init_roms(void); + +void sti_init_graph(struct sti_struct *sti); +void sti_inq_conf(struct sti_struct *sti); +void sti_putc(struct sti_struct *sti, int c, int y, int x); +void sti_set(struct sti_struct *sti, int src_y, int src_x, + int height, int width, u8 color); +void sti_clear(struct sti_struct *sti, int src_y, int src_x, + int height, int width); +void sti_bmove(struct sti_struct *sti, int src_y, int src_x, + int dst_y, int dst_x, int height, int width); + +/* XXX: this probably should not be here, but we rely on STI being + initialized early and independently of stifb at the moment, so + there's no other way for stifb to find it. */ +extern struct sti_struct default_sti; diff --git a/drivers/video/sticon-bmode.c b/drivers/video/sticon-bmode.c new file mode 100644 index 000000000..e401cbfcd --- /dev/null +++ b/drivers/video/sticon-bmode.c @@ -0,0 +1,906 @@ +/* +TPG CVS users: please don't commit changes to this file directly, send +them to prumpf@tux.org and wait for a new version instead. Otherwise, +your changes will get lost when prumpf releases the next version, as +this file *will* be replaced with it. You have been warned. + +2000-05-30, <deller@gmx.de> +*/ +#if 1 +#define DPRINTK(x) printk x +#else +#define DPRINTK(x) +#endif + +/* + * linux/drivers/video/sticon.c - console driver using HP's STI firmware + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + * Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c, + * which were + * + * Created 28 Sep 1997 by Geert Uytterhoeven + * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 + * Copyright (C) 1991, 1992 Linus Torvalds + * 1995 Jay Estabrook + * Copyright (C) 1995 Geert Uytterhoeven + * Copyright (C) 1993 Bjoern Brauel + * Roman Hodek + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * Martin Apel + * with work by Guenther Kelleter + * Martin Schaller + * Andreas Schwab + * Emmanuel Marty (core@ggi-project.org) + * Jakub Jelinek (jj@ultra.linux.cz) + * Martin Mares <mj@ucw.cz> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +/* + * TODO: + * - call STI in virtual mode rather than in real mode + * - support for PCI-only STI ROMs (which don't have a traditional region + * list) + * - safe detection (i.e. verify there is a graphics device at a given + * address first, not just read a random device's io space) + * - support for multiple STI devices in one machine + * - support for byte-mode STI ROMs + * - support for just using STI to switch to a colour fb (stifb ?) + * - try to make it work on m68k hp workstations ;) + */ + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/kd.h> +#include <linux/malloc.h> +#include <linux/vt_kern.h> +#include <linux/selection.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/delay.h> + +#include <asm/io.h> +#include <asm/real.h> + +#include <linux/module.h> +#include <linux/fb.h> +#include <linux/smp.h> + +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#include <video/fbcon.h> +#include <video/font.h> + +#include "sti-bmode.h" + +/* The latency of the STI functions cannot really be reduced by setting + * this to 0; STI doesn't seem to be designed to allow calling a different + * function (or the same function with different arguments) after a + * function exited with 1 as return value. + * + * As all of the functions below could be called from interrupt context, + * we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1) + * block. Really bad latency there. + * + * Probably the best solution to all this is have the generic code manage + * the screen buffer and a kernel thread to call STI occasionally. + * + * Luckily, the frame buffer guys have the same problem so we can just wait + * for them to fix it and steal their solution. prumpf + * + * Actually, another long-term viable solution is to completely do STI + * support in userspace - that way we avoid the potential license issues + * of using proprietary fonts, too. */ + +#define STI_WAIT 1 +#define STI_PTR(p) ( (typeof(p)) virt_to_phys(p)) +#define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) ) + +static struct sti_struct default_sti = { + SPIN_LOCK_UNLOCKED, +}; + +static struct sti_font_flags default_font_flags = { + STI_WAIT, 0, 0, NULL +}; + +/* The colour indices used by STI are + * 0 - Black + * 1 - White + * 2 - Red + * 3 - Yellow/Brown + * 4 - Green + * 5 - Cyan + * 6 - Blue + * 7 - Magenta + * + * So we have the same colours as VGA (basically one bit each for R, G, B), + * but have to translate them, anyway. */ + +static u8 col_trans[8] = { + 0, 6, 4, 5, + 2, 7, 3, 1 +}; + +#define c_fg(sti, c) col_trans[((c>> 8) & 7)] +#define c_bg(sti, c) col_trans[((c>>11) & 7)] +#define c_index(sti, c) (c&0xff) + +#define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x) +#define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y) +#define sti_font_x(sti) (STI_U8(PTR_STI(sti->font)->width)) +#define sti_font_y(sti) (STI_U8(PTR_STI(sti->font)->height)) + +static struct sti_init_flags default_init_flags = { + STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL +}; + +static void sti_init_graph(struct sti_struct *sti) +{ + struct sti_init_inptr_ext inptr_ext = { + 0, { 0 }, 0, NULL + }; + struct sti_init_inptr inptr = { + 3, STI_PTR(&inptr_ext) + }; + struct sti_init_outptr outptr = { 0 }; + unsigned long flags; + s32 ret; + + spin_lock_irqsave(&sti->lock, flags); + + ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr, + &outptr, sti->glob_cfg); + + spin_unlock_irqrestore(&sti->lock, flags); + + sti->text_planes = outptr.text_planes; +} + +#if 0 +static struct sti_conf_flags default_conf_flags = { + STI_WAIT, 0, NULL +}; + +static void sti_inq_conf(struct sti_struct *sti) +{ + struct sti_conf_inptr inptr = { NULL }; + struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL }; + struct sti_conf_outptr outptr = { + ext_ptr: STI_PTR(&outptr_ext) + }; + unsigned long flags; + s32 ret; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->inq_conf, &default_conf_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} +#endif + +static void sti_putc(struct sti_struct *sti, int c, int y, int x) +{ + struct sti_font_inptr inptr = { + (u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c), + x * sti_font_x(sti), y * sti_font_y(sti), NULL + }; + struct sti_font_outptr outptr = { + 0, NULL + }; + s32 ret; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->font_unpmv, &default_font_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + +static struct sti_blkmv_flags clear_blkmv_flags = { + STI_WAIT, 1, 1, 0, 0, NULL +}; + +static void sti_set(struct sti_struct *sti, int src_y, int src_x, + int height, int width, u8 color) +{ + struct sti_blkmv_inptr inptr = { + color, color, + src_x, src_y , + src_x, src_y , + width, height, + NULL + }; + struct sti_blkmv_outptr outptr = { 0, NULL }; + s32 ret = 0; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &clear_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + +static void sti_clear(struct sti_struct *sti, int src_y, int src_x, + int height, int width) +{ + struct sti_blkmv_inptr inptr = { + 0, 0, + src_x * sti_font_x(sti), src_y * sti_font_y(sti), + src_x * sti_font_x(sti), src_y * sti_font_y(sti), + width * sti_font_x(sti), height* sti_font_y(sti), + NULL + }; + struct sti_blkmv_outptr outptr = { 0, NULL }; + s32 ret = 0; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &clear_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + +static struct sti_blkmv_flags default_blkmv_flags = { + STI_WAIT, 0, 0, 0, 0, NULL +}; + +static void sti_bmove(struct sti_struct *sti, int src_y, int src_x, + int dst_y, int dst_x, int height, int width) +{ + struct sti_blkmv_inptr inptr = { + 0, 0, + src_x * sti_font_x(sti), src_y * sti_font_y(sti), + dst_x * sti_font_x(sti), dst_y * sti_font_y(sti), + width * sti_font_x(sti), height* sti_font_y(sti), + NULL + }; + struct sti_blkmv_outptr outptr = { 0, NULL }; + s32 ret = 0; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &default_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + + +/* STICON */ + +static const char __init *sticon_startup(void) +{ + return "STI console"; +} + +static int sticon_set_palette(struct vc_data *c, unsigned char *table) +{ + return -EINVAL; +} +static int sticon_font_op(struct vc_data *c, struct console_font_op *op) +{ + return -ENOSYS; +} + +static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) +{ + sti_putc(&default_sti, c, ypos, xpos); +} + +static void sticon_putcs(struct vc_data *conp, const unsigned short *s, + int count, int ypos, int xpos) +{ + while(count--) { + sti_putc(&default_sti, *s++, ypos, xpos++); + } +} + +static void sticon_cursor(struct vc_data *conp, int mode) +{ +} + +static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, + int count) +{ + struct sti_struct *sti = &default_sti; + + if(console_blanked) + return 0; + + sticon_cursor(conp, CM_ERASE); + + switch(dir) { + case SM_UP: + sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols); + sti_clear(sti, b-count, 0, count, conp->vc_cols); + + break; + + case SM_DOWN: + sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols); + sti_clear(sti, t, 0, count, conp->vc_cols); + + break; + } + + return 0; +} + +static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) +{ + sti_bmove(&default_sti, sy, sx, dy, dx, height, width); +} + +static void sticon_init(struct vc_data *c, int init) +{ + struct sti_struct *sti = &default_sti; + int vc_cols, vc_rows; + + sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0); + c->vc_can_do_color = 1; + vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti); + vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti); + + vc_resize_con(vc_rows, vc_cols, c->vc_num); +} + +static void sticon_deinit(struct vc_data *c) +{ +} + +static void sticon_clear(struct vc_data *conp, int sy, int sx, int height, + int width) +{ + sti_clear(&default_sti, sy, sx, height, width); +} + +static int sticon_switch(struct vc_data *conp) +{ + return 0; +} + +static int sticon_blank(struct vc_data *conp, int blank) +{ + return 0; +} + +static int sticon_scrolldelta(struct vc_data *conp, int lines) +{ + return 0; +} + +static int sticon_set_origin(struct vc_data *conp) +{ + return 0; +} + +static u16 *sticon_screen_pos(struct vc_data *conp, int offset) +{ + return NULL; +} + +static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py) +{ + return 0; +} + +static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse) +{ + u8 attr = ((color & 0x70) >> 1) | ((color & 7)); + + if(reverse) { + color = ((color>>3)&0x7) | ((color &0x7)<<3); + } + + + return attr; +} + +static struct consw sti_con = { + con_startup: sticon_startup, + con_init: sticon_init, + con_deinit: sticon_deinit, + con_clear: sticon_clear, + con_putc: sticon_putc, + con_putcs: sticon_putcs, + con_cursor: sticon_cursor, + con_scroll: sticon_scroll, + con_bmove: sticon_bmove, + con_switch: sticon_switch, + con_blank: sticon_blank, + con_font_op: sticon_font_op, + con_set_palette: sticon_set_palette, + con_scrolldelta: sticon_scrolldelta, + con_set_origin: sticon_set_origin, + con_save_screen: NULL, + con_build_attr: sticon_build_attr, + con_invert_region: NULL, + con_screen_pos: sticon_screen_pos, + con_getxy: sticon_getxy, +}; + +#include <asm/pgalloc.h> /* need cache flush routines */ +static void __init sti_rom_copy(unsigned long base, unsigned long offset, + unsigned long count, void *dest) +{ + void *savedest = dest; + int savecount = count; + + while(count >= 4) { + count -= 4; + *(u32 *)dest = gsc_readl(base + offset); +#if 0 + DPRINTK(("%08x\n", *(u32 *)dest)); + if(*(u32 *)dest == 0x64646464) { + DPRINTK(("!!!!\n")); + { u32 foo = 0; while(foo += 0x100); } + } +#endif + offset += 4; + dest += 4; + } + while(count) { + count--; + *(u8 *)dest = gsc_readb(base + offset); + offset++; + dest++; + } + __flush_dcache_range(dest, count); + __flush_icache_range(dest, count); +} + +static void dump_sti_rom(struct sti_rom *rom) +{ + printk("STI byte mode ROM type %d\n", STI_U8(rom->type)); + printk(" supports %d monitors\n", STI_U8(rom->num_mons)); + printk(" conforms to STI ROM spec revision %d.%02x\n", + STI_U8(rom->revno[0]) >> 4, STI_U8(rom->revno[0]) & 0x0f); + printk(__FUNCTION__ ": %d\n", __LINE__); + printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n", + (unsigned int) STI_U8(rom->graphics_id[0]), + (unsigned int) STI_U8(rom->graphics_id[1]), + (unsigned int) STI_U8(rom->graphics_id[2]), + (unsigned int) STI_U8(rom->graphics_id[3]), + (unsigned int) STI_U8(rom->graphics_id[4]), + (unsigned int) STI_U8(rom->graphics_id[5]), + (unsigned int) STI_U8(rom->graphics_id[6]), + (unsigned int) STI_U8(rom->graphics_id[7])); + printk(__FUNCTION__ ": %d\n", __LINE__); + printk(" font start %08x\n", STI_U32(rom->font_start)); + printk(__FUNCTION__ ": %d\n", __LINE__); + printk(" region list %08x\n", STI_U32(rom->region_list)); + printk(__FUNCTION__ ": %d\n", __LINE__); + printk(" init_graph %08x\n", STI_U32(rom->init_graph)); + printk(__FUNCTION__ ": %d\n", __LINE__); + printk(" alternate code type %d\n", STI_U8(rom->alt_code_type)); + printk(__FUNCTION__ ": %d\n", __LINE__); +} + +static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom, + struct sti_rom *raw_rom) +{ + struct sti_rom_font *raw_font; + struct sti_cooked_font *cooked_font; + struct sti_rom_font *font_start; + + cooked_font = + kmalloc(sizeof *cooked_font, GFP_KERNEL); + if(!cooked_font) + return; + + cooked_rom->font_start = cooked_font; + +#if 0 + DPRINTK(("%p = %p + %08x\n", + ((void *)raw_rom) + (STI_U32(raw_rom->font_start)), + ((void *)raw_rom), (STI_U32(raw_rom->font_start)))); +#endif + raw_font = ((void *)raw_rom) + STI_U32(raw_rom->font_start) - 3; + + font_start = raw_font; + cooked_font->raw = raw_font; + + DPRINTK(("next font %08x\n", STI_U32(raw_font->next_font))); + + while(0 && STI_U32(raw_font->next_font)) { + raw_font = ((void *)font_start) + STI_U32(raw_font->next_font); + + cooked_font->next_font = + kmalloc(sizeof *cooked_font, GFP_KERNEL); + if(!cooked_font->next_font) + return; + + cooked_font = cooked_font->next_font; + +// cooked_font->raw = raw_font; + + DPRINTK(("raw_font %p\n", + raw_font)); + DPRINTK(("next_font %08x %p\n", + STI_U32(raw_font->next_font), + ((void *)font_start) + STI_U32(raw_font->next_font))); + } + + cooked_font->next_font = NULL; +} + +static unsigned long __init sti_cook_function(void *function, + u32 size) +{ + sti_u32 *func = (sti_u32 *)function; + u32 *ret; + int i; + + ret = kmalloc(size, GFP_KERNEL); + if(!ret) { + printk(KERN_ERR __FILE__ ": could not get memory.\n"); + return 0; + } + + for(i=0; i<(size/4); i++) + ret[i] = STI_U32(func[i]); + + flush_all_caches(); + + return virt_to_phys(ret); +} + +static int font_index, font_height, font_width; + +static int __init sti_search_font(struct sti_cooked_rom *rom, + int height, int width) +{ + struct sti_cooked_font *font; + int i = 0; + + for(font = rom->font_start; font; font = font->next_font, i++) { + if((STI_U8(font->raw->width) == width) && + (STI_U8(font->raw->height) == height)) + return i; + } + + return 0; +} + +static struct sti_cooked_font * __init +sti_select_font(struct sti_cooked_rom *rom) +{ + struct sti_cooked_font *font; + int i; + + if(font_width && font_height) + font_index = sti_search_font(rom, font_height, font_width); + + for(font = rom->font_start, i = font_index; + font && (i > 0); + font = font->next_font, i--); + + if(font) + return font; + else + return rom->font_start; +} + +/* address is a pointer to a word mode or pci rom */ +static struct sti_struct * __init sti_read_rom(unsigned long address) +{ + struct sti_struct *ret = NULL; + struct sti_cooked_rom *cooked = NULL; + struct sti_rom *raw = NULL; + unsigned long size; + + ret = &default_sti; + + if(!ret) + goto out_err; + + cooked = kmalloc(sizeof *cooked, GFP_KERNEL); + raw = kmalloc(sizeof *raw, GFP_KERNEL); + + if(!(raw && cooked)) + goto out_err; + + /* reallocate raw */ + sti_rom_copy(address, 0, sizeof *raw, raw); + + dump_sti_rom(raw); + + size = STI_U32(raw->last_addr) + 1; + size = 128*1024; +// DPRINTK(("size %08lx\n", size)); +// DPRINTK(("font_start %08x\n", STI_U32(raw->font_start))); +// kfree(raw); + raw = kmalloc(size, GFP_KERNEL); + if(!raw) + goto out_err; + sti_rom_copy(address, 0, size-1, raw); + + sti_cook_fonts(cooked, raw); +// sti_cook_regions(cooked, raw); +// sti_cook_functions(cooked, raw); + + if(STI_U32(raw->region_list)) { + struct sti_rom_region *region = + ((void *)raw) + STI_U32(raw->region_list) - 3; + +// DPRINTK(("region_list %08x\n", STI_U32(raw->region_list))); + + ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME!! */ + + ret->regions[0] = STI_U32(region[0].region); + ret->regions[1] = STI_U32(region[1].region); + ret->regions[2] = STI_U32(region[2].region); + ret->regions[3] = STI_U32(region[3].region); + ret->regions[4] = STI_U32(region[4].region); + ret->regions[5] = STI_U32(region[5].region); + ret->regions[6] = STI_U32(region[6].region); + ret->regions[7] = STI_U32(region[7].region); + } + + address = virt_to_phys(raw); + +#if 0 + DPRINTK(("init_graph %08x %08x\n" + "state_mgmt %08x %08x\n" + "font_unpmv %08x %08x\n" + "block_move %08x %08x\n" + "self_test %08x %08x\n" + "excep_hdlr %08x %08x\n" + "irq_conf %08x %08x\n" + "set_cm_e %08x %08x\n" + "dma_ctrl %08x %08x\n" + "flow_ctrl %08x %08x\n" + "user_timin %08x %08x\n" + "process_m %08x %08x\n" + "sti_util %08x %08x\n" + "end_addr %08x %08x\n", + STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k), + STI_U32(raw->state_mgmt), STI_U32(raw->state_mgmt_m68k), + STI_U32(raw->font_unpmv), STI_U32(raw->font_unpmv_m68k), + STI_U32(raw->block_move), STI_U32(raw->block_move_m68k), + STI_U32(raw->self_test), STI_U32(raw->self_test_m68k), + STI_U32(raw->excep_hdlr), STI_U32(raw->excep_hdlr_m68k), + STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k), + STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k), + STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k), + STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k), + STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k), + STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k), + STI_U32(raw->init_graph), STI_U32(raw->init_graph_m68k), + STI_U32(raw->end_addr), STI_U32(raw->end_addr_m68k) ) ); +#endif + + ret->init_graph = sti_cook_function(((void *)raw)+STI_U32(raw->init_graph)-3, + (STI_U32(raw->state_mgmt) - + STI_U32(raw->init_graph))/4); + + + ret->font_unpmv = sti_cook_function(((void *)raw)+STI_U32(raw->font_unpmv)-3, + (STI_U32(raw->block_move) - + STI_U32(raw->font_unpmv))/4); + + ret->block_move = sti_cook_function(((void *)raw)+STI_U32(raw->block_move)-3, + (STI_U32(raw->self_test) - + STI_U32(raw->block_move))/4); + + ret->inq_conf = sti_cook_function(((void *)raw)+STI_U32(raw->inq_conf), + STI_U32(raw->set_cm_entry) - + STI_U32(raw->inq_conf)); + + ret->rom = cooked; + ret->rom->raw = raw; + + ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw); + + return ret; + +out_err: + if(raw) + kfree(raw); + if(cooked) + kfree(cooked); + + return NULL; +} + +#if 0 +static void dump_globcfg_ext(struct sti_glob_cfg_ext *cfg) +{ + DPRINTK(("monitor %d\n" + "in friendly mode: %d\n" + "power consumption %d watts\n" + "freq ref %d\n" + "sti_mem_addr %p\n", + cfg->curr_mon, + cfg->friendly_boot, + cfg->power, + cfg->freq_ref, + cfg->sti_mem_addr)); +} + +static void dump_globcfg(struct sti_glob_cfg *glob_cfg) +{ + DPRINTK(("%d text planes\n" + "%4d x %4d screen resolution\n" + "%4d x %4d offscreen\n" + "%4d x %4d layout\n" + "regions at %08x %08x %08x %08x\n" + "regions at %08x %08x %08x %08x\n" + "reent_lvl %d\n" + "save_addr %p\n", + glob_cfg->text_planes, + glob_cfg->onscreen_x, glob_cfg->onscreen_y, + glob_cfg->offscreen_x, glob_cfg->offscreen_y, + glob_cfg->total_x, glob_cfg->total_y, + glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1], + glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3], + glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5], + glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7], + glob_cfg->reent_lvl, + glob_cfg->save_addr)); + dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr)); +} +#endif + +static void __init sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa, + unsigned long rom_address) +{ + struct sti_glob_cfg *glob_cfg; + struct sti_glob_cfg_ext *glob_cfg_ext; + void *save_addr; + void *sti_mem_addr; + + glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL); + glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL); + save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL); + sti_mem_addr = kmalloc(1024, GFP_KERNEL); + + if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr)) + return; + + memset(glob_cfg, 0, sizeof *glob_cfg); + memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext); + memset(save_addr, 0, 1024); + memset(sti_mem_addr, 0, 1024); + + glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext); + glob_cfg->save_addr = STI_PTR(save_addr); + glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address; + glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa; + glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa; + glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa; + glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa; + glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa; + glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa; + glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa; + + glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr); + + sti->glob_cfg = STI_PTR(glob_cfg); +} + +static void __init sti_try_rom(unsigned long address, unsigned long hpa) +{ + struct sti_struct *sti = NULL; + u16 sig; + + /* if we can't read the ROM, bail out early. Not being able + * to read the hpa is okay, for romless sti */ + if(pdc_add_valid((void*)address)) + return; + + printk("found potential STI ROM at %08lx\n", address); + + sig = le16_to_cpu(gsc_readw(address)); + + if((sig&0xff) == 0x01) { + sti = sti_read_rom(address); + } + + if(sig == 0x0303) { + printk("STI word mode ROM at %08lx, ignored\n", + address); + + sti = NULL; + } + + if(!sti) + return; + + /* this is hacked. We need a better way to find out the HPA for + * romless STI (eg search for the graphics devices we know about + * by sversion) */ + if (!pdc_add_valid((void *)0xf5000000)) DPRINTK(("f4000000 b\n")); + if (!pdc_add_valid((void *)0xf7000000)) DPRINTK(("f6000000 b\n")); + if (!pdc_add_valid((void *)0xf9000000)) DPRINTK(("f8000000 b\n")); + if (!pdc_add_valid((void *)0xfb000000)) DPRINTK(("fa000000 b\n")); + sti_init_glob_cfg(sti, hpa, address); + + sti_init_graph(sti); + + //sti_inq_conf(sti); +#if !defined(SERIAL_CONSOLE) + { + extern void pdc_console_die(void); + pdc_console_die(); + } +#endif + + take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1); + + /* sti_inq_conf(sti); */ +} + +static unsigned long sti_address; +static unsigned long sti_hpa; + +static void __init sti_init_roms(void) +{ + /* handle the command line */ + if(sti_address && sti_hpa) { + sti_try_rom(sti_address, sti_hpa); + + return; + } + + /* 712, 715, some other boxes don't have a separate STI ROM, + * but use part of the regular flash */ + if(PAGE0->proc_sti) { + printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti); + if(!pdc_add_valid((void *)0xf9000000)) + sti_try_rom(PAGE0->proc_sti, 0xf8000000); + else if(!pdc_add_valid((void *)0xf5000000)) + sti_try_rom(PAGE0->proc_sti, 0xf4000000); + else if(!pdc_add_valid((void *)0xf7000000)) + sti_try_rom(PAGE0->proc_sti, 0xf6000000); + else if(!pdc_add_valid((void *)0xfb000000)) + sti_try_rom(PAGE0->proc_sti, 0xfa000000); + } + + /* standard locations for GSC graphic devices */ + if(!pdc_add_valid((void *)0xf4000000)) + sti_try_rom(0xf4000000, 0xf4000000); + if(!pdc_add_valid((void *)0xf6000000)) + sti_try_rom(0xf6000000, 0xf6000000); + if(!pdc_add_valid((void *)0xf8000000)) + sti_try_rom(0xf8000000, 0xf8000000); + if(!pdc_add_valid((void *)0xfa000000)) + sti_try_rom(0xfa000000, 0xfa000000); +} + +static int __init sti_init(void) +{ + printk("searching for byte mode STI ROMs\n"); + sti_init_roms(); + return 0; +} + +module_init(sti_init) diff --git a/drivers/video/sticon.c b/drivers/video/sticon.c new file mode 100644 index 000000000..ba3f1167d --- /dev/null +++ b/drivers/video/sticon.c @@ -0,0 +1,229 @@ +/* + * linux/drivers/video/sticon.c - console driver using HP's STI firmware + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + * Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c, + * which were + * + * Created 28 Sep 1997 by Geert Uytterhoeven + * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 + * Copyright (C) 1991, 1992 Linus Torvalds + * 1995 Jay Estabrook + * Copyright (C) 1995 Geert Uytterhoeven + * Copyright (C) 1993 Bjoern Brauel + * Roman Hodek + * Copyright (C) 1993 Hamish Macdonald + * Greg Harp + * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] + * + * with work by William Rucklidge (wjr@cs.cornell.edu) + * Geert Uytterhoeven + * Jes Sorensen (jds@kom.auc.dk) + * Martin Apel + * with work by Guenther Kelleter + * Martin Schaller + * Andreas Schwab + * Emmanuel Marty (core@ggi-project.org) + * Jakub Jelinek (jj@ultra.linux.cz) + * Martin Mares <mj@ucw.cz> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +/* + * TODO: + * - call STI in virtual mode rather than in real mode + * - support for PCI-only STI ROMs (which don't have a traditional region + * list) + * - safe detection (i.e. verify there is a graphics device at a given + * address first, not just read a random device's io space) + * - support for multiple STI devices in one machine + * - support for byte-mode STI ROMs + * - support for just using STI to switch to a colour fb (stifb ?) + * - try to make it work on m68k hp workstations ;) + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/console_struct.h> +#include <linux/errno.h> +#include <linux/vt_kern.h> +#include <linux/selection.h> + +#include <asm/io.h> + +#include "sti.h" + +/* STICON */ + +static const char * __init +sticon_startup(void) +{ + return "STI console"; +} + +static int +sticon_set_palette(struct vc_data *c, unsigned char *table) +{ + return -EINVAL; +} +static int +sticon_font_op(struct vc_data *c, struct console_font_op *op) +{ + return -ENOSYS; +} + +static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) +{ + sti_putc(&default_sti, c, ypos, xpos); +} + +static void sticon_putcs(struct vc_data *conp, const unsigned short *s, + int count, int ypos, int xpos) +{ + while(count--) { + sti_putc(&default_sti, *s++, ypos, xpos++); + } +} + +static void sticon_cursor(struct vc_data *conp, int mode) +{ +} + +static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, + int count) +{ + struct sti_struct *sti = &default_sti; + + if(console_blanked) + return 0; + + sticon_cursor(conp, CM_ERASE); + + switch(dir) { + case SM_UP: + sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols); + sti_clear(sti, b-count, 0, count, conp->vc_cols); + + break; + + case SM_DOWN: + sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols); + sti_clear(sti, t, 0, count, conp->vc_cols); + + break; + } + + return 0; +} + +static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, + int height, int width) +{ + sti_bmove(&default_sti, sy, sx, dy, dx, height, width); +} + +static void sticon_init(struct vc_data *c, int init) +{ + struct sti_struct *sti = &default_sti; + int vc_cols, vc_rows; + + sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0); + c->vc_can_do_color = 1; + vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti); + vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti); + + vc_resize_con(vc_rows, vc_cols, c->vc_num); +} + +static void sticon_deinit(struct vc_data *c) +{ +} + +static void sticon_clear(struct vc_data *conp, int sy, int sx, int height, + int width) +{ + sti_clear(&default_sti, sy, sx, height, width); +} + +static int sticon_switch(struct vc_data *conp) +{ + return 0; +} + +static int sticon_blank(struct vc_data *conp, int blank) +{ + return 0; +} + +static int sticon_scrolldelta(struct vc_data *conp, int lines) +{ + return 0; +} + +static int sticon_set_origin(struct vc_data *conp) +{ + return 0; +} + +static u16 *sticon_screen_pos(struct vc_data *conp, int offset) +{ + return NULL; +} + +static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py) +{ + return 0; +} + +static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse) +{ + u8 attr = ((color & 0x70) >> 1) | ((color & 7)); + + if(reverse) { + color = ((color>>3)&0x7) | ((color &0x7)<<3); + } + + + return attr; +} + +struct consw sti_con = { + con_startup: sticon_startup, + con_init: sticon_init, + con_deinit: sticon_deinit, + con_clear: sticon_clear, + con_putc: sticon_putc, + con_putcs: sticon_putcs, + con_cursor: sticon_cursor, + con_scroll: sticon_scroll, + con_bmove: sticon_bmove, + con_switch: sticon_switch, + con_blank: sticon_blank, + con_font_op: sticon_font_op, + con_set_palette: sticon_set_palette, + con_scrolldelta: sticon_scrolldelta, + con_set_origin: sticon_set_origin, + con_save_screen: NULL, + con_build_attr: sticon_build_attr, + con_invert_region: NULL, + con_screen_pos: sticon_screen_pos, + con_getxy: sticon_getxy, +}; + +static int __init sti_init(void) +{ + printk("searching for word mode STI ROMs\n"); + if (sti_init_roms()) { + pdc_console_die(); + take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1); + return 0; + } else + return -ENODEV; +} + +module_init(sti_init) diff --git a/drivers/video/sticore.c b/drivers/video/sticore.c new file mode 100644 index 000000000..56e7f43ce --- /dev/null +++ b/drivers/video/sticore.c @@ -0,0 +1,598 @@ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/init.h> + +#include <asm/uaccess.h> +#include <asm/pgalloc.h> +#include <asm/io.h> + +#include "sti.h" + +struct sti_struct default_sti = { + SPIN_LOCK_UNLOCKED, +}; + +static struct sti_font_flags default_font_flags = { + STI_WAIT, 0, 0, NULL +}; + +/* The colour indices used by STI are + * 0 - Black + * 1 - White + * 2 - Red + * 3 - Yellow/Brown + * 4 - Green + * 5 - Cyan + * 6 - Blue + * 7 - Magenta + * + * So we have the same colours as VGA (basically one bit each for R, G, B), + * but have to translate them, anyway. */ + +static u8 col_trans[8] = { + 0, 6, 4, 5, + 2, 7, 3, 1 +}; + +#define c_fg(sti, c) col_trans[((c>> 8) & 7)] +#define c_bg(sti, c) col_trans[((c>>11) & 7)] +#define c_index(sti, c) (c&0xff) + +static struct sti_init_flags default_init_flags = { + STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL +}; + +void +sti_init_graph(struct sti_struct *sti) +{ + struct sti_init_inptr_ext inptr_ext = { + 0, { 0 }, 0, NULL + }; + struct sti_init_inptr inptr = { + 3, STI_PTR(&inptr_ext) + }; + struct sti_init_outptr outptr = { 0 }; + unsigned long flags; + s32 ret; + + spin_lock_irqsave(&sti->lock, flags); + + ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr, + &outptr, sti->glob_cfg); + + spin_unlock_irqrestore(&sti->lock, flags); + + sti->text_planes = outptr.text_planes; +} + +static struct sti_conf_flags default_conf_flags = { + STI_WAIT, 0, NULL +}; + +void +sti_inq_conf(struct sti_struct *sti) +{ + struct sti_conf_inptr inptr = { NULL }; + struct sti_conf_outptr_ext outptr_ext = { future_ptr: NULL }; + struct sti_conf_outptr outptr = { + ext_ptr: STI_PTR(&outptr_ext) + }; + unsigned long flags; + s32 ret; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->inq_conf, &default_conf_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + +void +sti_putc(struct sti_struct *sti, int c, int y, int x) +{ + struct sti_font_inptr inptr = { + (u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c), + x * sti_font_x(sti), y * sti_font_y(sti), NULL + }; + struct sti_font_outptr outptr = { + 0, NULL + }; + s32 ret; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->font_unpmv, &default_font_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + +static struct sti_blkmv_flags clear_blkmv_flags = { + STI_WAIT, 1, 1, 0, 0, NULL +}; + +void +sti_set(struct sti_struct *sti, int src_y, int src_x, + int height, int width, u8 color) +{ + struct sti_blkmv_inptr inptr = { + color, color, + src_x, src_y , + src_x, src_y , + width, height, + NULL + }; + struct sti_blkmv_outptr outptr = { 0, NULL }; + s32 ret = 0; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &clear_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + +void +sti_clear(struct sti_struct *sti, int src_y, int src_x, + int height, int width) +{ + struct sti_blkmv_inptr inptr = { + 0, 0, + src_x * sti_font_x(sti), src_y * sti_font_y(sti), + src_x * sti_font_x(sti), src_y * sti_font_y(sti), + width * sti_font_x(sti), height* sti_font_y(sti), + NULL + }; + struct sti_blkmv_outptr outptr = { 0, NULL }; + s32 ret = 0; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &clear_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + +static struct sti_blkmv_flags default_blkmv_flags = { + STI_WAIT, 0, 0, 0, 0, NULL +}; + +void +sti_bmove(struct sti_struct *sti, int src_y, int src_x, + int dst_y, int dst_x, int height, int width) +{ + struct sti_blkmv_inptr inptr = { + 0, 0, + src_x * sti_font_x(sti), src_y * sti_font_y(sti), + dst_x * sti_font_x(sti), dst_y * sti_font_y(sti), + width * sti_font_x(sti), height* sti_font_y(sti), + NULL + }; + struct sti_blkmv_outptr outptr = { 0, NULL }; + s32 ret = 0; + unsigned long flags; + + do { + spin_lock_irqsave(&sti->lock, flags); + ret = STI_CALL(sti->block_move, &default_blkmv_flags, + &inptr, &outptr, sti->glob_cfg); + spin_unlock_irqrestore(&sti->lock, flags); + } while(ret == 1); +} + + +static void __init +sti_rom_copy(unsigned long base, unsigned long offset, + unsigned long count, void *dest) +{ + void *savedest = dest; + int savecount = count; + + while(count >= 4) { + count -= 4; + *(u32 *)dest = gsc_readl(base + offset); + offset += 4; + dest += 4; + } + while(count) { + count--; + *(u8 *)dest = gsc_readb(base + offset); + offset++; + dest++; + } + __flush_dcache_range((unsigned long) dest, count); + __flush_icache_range((unsigned long) dest, count); +} + +static void dump_sti_rom(struct sti_rom *rom) +{ + printk("STI word mode ROM type %d\n", rom->type[3]); + printk(" supports %d monitors\n", rom->num_mons); + printk(" conforms to STI ROM spec revision %d.%02x\n", + rom->revno[0] >> 4, rom->revno[0] & 0x0f); + printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n", + rom->graphics_id[0], + rom->graphics_id[1], + rom->graphics_id[2], + rom->graphics_id[3], + rom->graphics_id[4], + rom->graphics_id[5], + rom->graphics_id[6], + rom->graphics_id[7]); + printk(" font start %08x\n", rom->font_start); + printk(" region list %08x\n", rom->region_list); + printk(" init_graph %08x\n", rom->init_graph); + printk(" alternate code type %d\n", rom->alt_code_type); +} + +static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom, + struct sti_rom *raw_rom) +{ + struct sti_rom_font *raw_font; + struct sti_cooked_font *cooked_font; + struct sti_rom_font *font_start; + + cooked_font = + kmalloc(sizeof *cooked_font, GFP_KERNEL); + if(!cooked_font) + return; + + cooked_rom->font_start = cooked_font; + + raw_font = ((void *)raw_rom) + (raw_rom->font_start); + + font_start = raw_font; + cooked_font->raw = raw_font; + + while(raw_font->next_font) { + raw_font = ((void *)font_start) + (raw_font->next_font); + + cooked_font->next_font = + kmalloc(sizeof *cooked_font, GFP_KERNEL); + if(!cooked_font->next_font) + return; + + cooked_font = cooked_font->next_font; + + cooked_font->raw = raw_font; + } + + cooked_font->next_font = NULL; +} + +static int font_index, font_height, font_width; + +static int __init sti_font_setup(char *str) +{ + char *x; + + /* we accept sti_font=10x20, sti_font=10*20 or sti_font=7 style + * command lines. */ + + if((x = strchr(str, 'x')) || (x = strchr(str, '*'))) { + font_height = simple_strtoul(str, NULL, 0); + font_width = simple_strtoul(x+1, NULL, 0); + } else { + font_index = simple_strtoul(str, NULL, 0); + } + + return 0; +} + +__setup("sti_font=", sti_font_setup); + +static int __init sti_search_font(struct sti_cooked_rom *rom, + int height, int width) +{ + struct sti_cooked_font *font; + int i = 0; + + for(font = rom->font_start; font; font = font->next_font, i++) { + if((font->raw->width == width) && (font->raw->height == height)) + return i; + } + + return 0; +} + +static struct sti_cooked_font * __init +sti_select_font(struct sti_cooked_rom *rom) +{ + struct sti_cooked_font *font; + int i; + + if(font_width && font_height) + font_index = sti_search_font(rom, font_height, font_width); + + for(font = rom->font_start, i = font_index; + font && (i > 0); + font = font->next_font, i--); + + if(font) + return font; + else + return rom->font_start; +} + +static void __init +sti_dump_globcfg_ext(struct sti_glob_cfg_ext *cfg) +{ + printk( "monitor %d\n" + "in friendly mode: %d\n" + "power consumption %d watts\n" + "freq ref %d\n" + "sti_mem_addr %p\n", + cfg->curr_mon, + cfg->friendly_boot, + cfg->power, + cfg->freq_ref, + cfg->sti_mem_addr); +} + +void __init +sti_dump_globcfg(struct sti_glob_cfg *glob_cfg) +{ + printk( "%d text planes\n" + "%4d x %4d screen resolution\n" + "%4d x %4d offscreen\n" + "%4d x %4d layout\n" + "regions at %08x %08x %08x %08x\n" + "regions at %08x %08x %08x %08x\n" + "reent_lvl %d\n" + "save_addr %p\n", + glob_cfg->text_planes, + glob_cfg->onscreen_x, glob_cfg->onscreen_y, + glob_cfg->offscreen_x, glob_cfg->offscreen_y, + glob_cfg->total_x, glob_cfg->total_y, + glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1], + glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3], + glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5], + glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7], + glob_cfg->reent_lvl, + glob_cfg->save_addr); + sti_dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr)); +} + +static void __init +sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa, + unsigned long rom_address) +{ + struct sti_glob_cfg *glob_cfg; + struct sti_glob_cfg_ext *glob_cfg_ext; + void *save_addr; + void *sti_mem_addr; + + glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL); + glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL); + save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL); + sti_mem_addr = kmalloc(1024, GFP_KERNEL); + + if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr)) + return; + + memset(glob_cfg, 0, sizeof *glob_cfg); + memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext); + memset(save_addr, 0, 1024); + memset(sti_mem_addr, 0, 1024); + + glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext); + glob_cfg->save_addr = STI_PTR(save_addr); + glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address; + glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa; + glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa; + glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa; + glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa; + glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa; + glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa; + glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa; + + glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr); + + sti->glob_cfg = STI_PTR(glob_cfg); +} + +/* address is a pointer to a word mode or pci rom */ +static struct sti_struct * __init +sti_read_rom(unsigned long address) +{ + struct sti_struct *ret = NULL; + struct sti_cooked_rom *cooked = NULL; + struct sti_rom *raw = NULL; + unsigned long size; + + ret = &default_sti; + + if(!ret) + goto out_err; + + cooked = kmalloc(sizeof *cooked, GFP_KERNEL); + raw = kmalloc(sizeof *raw, GFP_KERNEL); + + if(!(raw && cooked)) + goto out_err; + + /* reallocate raw */ + sti_rom_copy(address, 0, sizeof *raw, raw); + + dump_sti_rom(raw); + + size = raw->last_addr; + /* kfree(raw); */ + raw = kmalloc(size, GFP_KERNEL); + if(!raw) + goto out_err; + sti_rom_copy(address, 0, size, raw); + + sti_cook_fonts(cooked, raw); +#if 0 + sti_cook_regions(cooked, raw); + sti_cook_functions(cooked, raw); +#endif + + if(raw->region_list) { + ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME */ + + memcpy(ret->regions, ((void *)raw)+raw->region_list, 32); + } + + address = virt_to_phys(raw); + + ret->font_unpmv = address+(raw->font_unpmv & 0x03ffffff); + ret->block_move = address+(raw->block_move & 0x03ffffff); + ret->init_graph = address+(raw->init_graph & 0x03ffffff); + ret->inq_conf = address+(raw->inq_conf & 0x03ffffff); + + ret->rom = cooked; + ret->rom->raw = raw; + + ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw); + + return ret; + +out_err: + if(raw) + kfree(raw); + if(cooked) + kfree(cooked); + + return NULL; +} + +static struct sti_struct * __init +sti_try_rom(unsigned long address, unsigned long hpa) +{ + struct sti_struct *sti = NULL; + u16 sig; + +test_rom: + /* if we can't read the ROM, bail out early. Not being able + * to read the hpa is okay, for romless sti */ + if(pdc_add_valid((void*)address)) + return NULL; + + printk("found potential STI ROM at %08lx\n", address); + + sig = le16_to_cpu(gsc_readw(address)); + + if((sig==0x55aa) || (sig==0xaa55)) { + address += le32_to_cpu(gsc_readl(address+8)); + printk("sig %04x, PCI STI ROM at %08lx\n", + sig, address); + + goto test_rom; + } + + if((sig&0xff) == 0x01) { + printk("STI byte mode ROM at %08lx, ignored\n", + address); + + sti = NULL; + } + + if(sig == 0x0303) { + printk("STI word mode ROM at %08lx\n", + address); + + sti = sti_read_rom(address); + } + + if (!sti) + return NULL; + + /* this is hacked. We need a better way to find out the HPA for + * romless STI (eg search for the graphics devices we know about + * by sversion) */ + if (!pdc_add_valid((void *)0xf5000000)) printk("f4000000 g\n"); + if (!pdc_add_valid((void *)0xf7000000)) printk("f6000000 g\n"); + if (!pdc_add_valid((void *)0xf9000000)) printk("f8000000 g\n"); + if (!pdc_add_valid((void *)0xfb000000)) printk("fa000000 g\n"); + sti_init_glob_cfg(sti, hpa, address); + + sti_init_graph(sti); + + sti_inq_conf(sti); + sti_dump_globcfg(PTR_STI(sti->glob_cfg)); + + return sti; +} + +static unsigned long sti_address; +static unsigned long sti_hpa; + +/* XXX: should build a list of STI ROMs */ +struct sti_struct * __init +sti_init_roms(void) +{ + struct sti_struct *tmp = NULL, *sti = NULL; + + /* handle the command line */ + if (sti_address && sti_hpa) { + return sti_try_rom(sti_address, sti_hpa); + } + + /* 712, 715, some other boxes don't have a separate STI ROM, + * but use part of the regular flash */ + if (PAGE0->proc_sti) { + printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti); + if (!pdc_add_valid((void *)0xf9000000)) + sti = sti_try_rom(PAGE0->proc_sti, 0xf8000000); + else if (!pdc_add_valid((void *)0xf5000000)) + sti = sti_try_rom(PAGE0->proc_sti, 0xf4000000); + else if (!pdc_add_valid((void *)0xf7000000)) + sti = sti_try_rom(PAGE0->proc_sti, 0xf6000000); + else if (!pdc_add_valid((void *)0xfb000000)) + sti = sti_try_rom(PAGE0->proc_sti, 0xfa000000); + + } + + /* standard locations for GSC graphic devices */ + if (!pdc_add_valid((void *)0xf4000000)) + tmp = sti_try_rom(0xf4000000, 0xf4000000); + sti = tmp ? tmp : sti; + if (!pdc_add_valid((void *)0xf6000000)) + tmp = sti_try_rom(0xf6000000, 0xf6000000); + sti = tmp ? tmp : sti; + if (!pdc_add_valid((void *)0xf8000000)) + tmp = sti_try_rom(0xf8000000, 0xf8000000); + sti = tmp ? tmp : sti; + if (!pdc_add_valid((void *)0xfa000000)) + tmp = sti_try_rom(0xfa000000, 0xfa000000); + sti = tmp ? tmp : sti; + + return sti; +} + +static int __init +sti_setup(char *str) +{ + char *end; + + if(strcmp(str, "pdc") == 0) { + sti_address = PAGE0->proc_sti; + + return 1; + } else { + sti_address = simple_strtoul(str, &end, 16); + + if((end == str) || (sti_address < 0xf0000000)) { + sti_address = 0; + return 0; + } + + sti_hpa = sti_address; + + return 1; + } + + return 0; +} + +__setup("sti=", sti_setup); diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c new file mode 100644 index 000000000..661ff29c5 --- /dev/null +++ b/drivers/video/stifb.c @@ -0,0 +1,230 @@ +/* + * linux/drivers/video/stifb.c - Generic frame buffer driver for HP + * workstations with STI (standard text interface) video firmware. + * + * Based on: + * linux/drivers/video/artistfb.c -- Artist frame buffer driver + * + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> + * + * based on skeletonfb, which was + * Created 28 Dec 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. */ + +/* + * Notes: + * + * This driver assumes that the video has been set up in 1bpp mode by + * the firmware. Since HP video tends to be planar rather than + * packed-pixel this will probably work anyway even if it isn't. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> + +#include <video/fbcon.h> + +#include "sti.h" + +static struct fb_ops stifb_ops; + +struct stifb_info { + struct fb_info_gen gen; + struct sti_struct *sti; +}; + +struct stifb_par { +}; + +static struct stifb_info fb_info; +static struct display disp; + +int stifb_init(void); +int stifb_setup(char*); + +extern struct display_switch fbcon_sti; + +/* ------------------- chipset specific functions -------------------------- */ + +static int +sti_encode_fix(struct fb_fix_screeninfo *fix, + const void *par, struct fb_info_gen *info) +{ + /* XXX: what about smem_len? */ + fix->smem_start = PTR_STI(fb_info.sti->glob_cfg)->region_ptrs[1]; + fix->type = FB_TYPE_PLANES; /* well, sort of */ + + return 0; +} + +static int +sti_decode_var(const struct fb_var_screeninfo *var, + void *par, struct fb_info_gen *info) +{ + return 0; +} + +static int +sti_encode_var(struct fb_var_screeninfo *var, + const void *par, struct fb_info_gen *info) +{ + var->xres = PTR_STI(fb_info.sti->glob_cfg)->onscreen_x; + var->yres = PTR_STI(fb_info.sti->glob_cfg)->onscreen_y; + var->xres_virtual = PTR_STI(fb_info.sti->glob_cfg)->total_x; + var->yres_virtual = PTR_STI(fb_info.sti->glob_cfg)->total_y; + var->xoffset = var->yoffset = 0; + + var->bits_per_pixel = 1; + var->grayscale = 0; + + return 0; +} + +static void +sti_get_par(void *par, struct fb_info_gen *info) +{ +} + +static void +sti_set_par(const void *par, struct fb_info_gen *info) +{ +} + +static int +sti_getcolreg(unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, struct fb_info *info) +{ + return 0; +} + +static int +sti_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + return 0; +} + +static void +sti_set_disp(const void *par, struct display *disp, + struct fb_info_gen *info) +{ + disp->screen_base = + (void *) PTR_STI(fb_info.sti->glob_cfg)->region_ptrs[1]; + disp->dispsw = &fbcon_sti; +} + +static void +sti_detect(void) +{ +} + +static int +sti_blank(int blank_mode, const struct fb_info *info) +{ + return 0; +} + +/* ------------ Interfaces to hardware functions ------------ */ + +struct fbgen_hwswitch sti_switch = { + detect: sti_detect, + encode_fix: sti_encode_fix, + decode_var: sti_decode_var, + encode_var: sti_encode_var, + get_par: sti_get_par, + set_par: sti_set_par, + getcolreg: sti_getcolreg, + setcolreg: sti_setcolreg, + pan_display: NULL, + blank: sti_blank, + set_disp: sti_set_disp +}; + + +/* ------------ Hardware Independent Functions ------------ */ + + /* + * Initialization + */ + +int __init +stifb_init(void) +{ + printk("searching for word mode STI ROMs\n"); + /* XXX: in the future this will return a list of ROMs */ + if ((fb_info.sti = sti_init_roms()) == NULL) + return -ENXIO; + + fb_info.gen.info.node = -1; + fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; + fb_info.gen.info.fbops = &stifb_ops; + fb_info.gen.info.disp = &disp; + fb_info.gen.info.changevar = NULL; + fb_info.gen.info.switch_con = &fbgen_switch; + fb_info.gen.info.updatevar = &fbgen_update_var; + fb_info.gen.info.blank = &fbgen_blank; + strcpy(fb_info.gen.info.modename, "STI Generic"); + fb_info.gen.fbhw = &sti_switch; + fb_info.gen.fbhw->detect(); + + /* This should give a reasonable default video mode */ + fbgen_get_var(&disp.var, -1, &fb_info.gen.info); + fbgen_do_set_var(&disp.var, 1, &fb_info.gen); + fbgen_set_disp(-1, &fb_info.gen); + fbgen_install_cmap(0, &fb_info.gen); + pdc_console_die(); + if (register_framebuffer(&fb_info.gen.info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename); + + return 0; +} + + + /* + * Cleanup + */ + +void +stifb_cleanup(struct fb_info *info) +{ + printk("stifb_cleanup: you're on crack\n"); +} + + +int __init +stifb_setup(char *options) +{ + /* XXX: we should take the resolution, bpp as command line arguments. */ + return 0; +} + + +/* ------------------------------------------------------------------------- */ + + +static struct fb_ops stifb_ops = { + owner: THIS_MODULE, + fb_open: NULL, + fb_release: NULL, + fb_get_fix: fbgen_get_fix, + fb_get_var: fbgen_get_var, + fb_set_var: fbgen_set_var, + fb_get_cmap: fbgen_get_cmap, + fb_set_cmap: fbgen_set_cmap, + fb_pan_display: fbgen_pan_display, + fb_ioctl: NULL +}; diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 4128c313e..d954dc02e 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -327,7 +327,6 @@ struct fb_info_tdfx { struct tdfxfb_par default_par; struct tdfxfb_par current_par; struct display disp; - struct display_switch dispsw; #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) union { #ifdef FBCON_HAS_CFB16 @@ -412,10 +411,10 @@ static int tdfxfb_encode_var(struct fb_var_screeninfo* var, static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix, const struct tdfxfb_par* par, const struct fb_info_tdfx* info); -static void tdfxfb_set_disp(struct display* disp, - struct fb_info_tdfx* info, - int bpp, - int accel); +static void tdfxfb_set_dispsw(struct display* disp, + struct fb_info_tdfx* info, + int bpp, + int accel); static int tdfxfb_getcolreg(u_int regno, u_int* red, u_int* green, @@ -1640,48 +1639,43 @@ static int tdfxfb_get_var(struct fb_var_screeninfo *var, return 0; } -static void tdfxfb_set_disp(struct display *disp, - struct fb_info_tdfx *info, - int bpp, - int accel) { +static void tdfxfb_set_dispsw(struct display *disp, + struct fb_info_tdfx *info, + int bpp, + int accel) { if (disp->dispsw && disp->conp) fb_con.con_cursor(disp->conp, CM_ERASE); switch(bpp) { #ifdef FBCON_HAS_CFB8 case 8: - info->dispsw = noaccel ? fbcon_cfb8 : fbcon_banshee8; - disp->dispsw = &info->dispsw; + disp->dispsw = noaccel ? &fbcon_cfb8 : &fbcon_banshee8; if (nohwcursor) fbcon_banshee8.cursor = NULL; break; #endif #ifdef FBCON_HAS_CFB16 case 16: - info->dispsw = noaccel ? fbcon_cfb16 : fbcon_banshee16; - disp->dispsw = &info->dispsw; + disp->dispsw = noaccel ? &fbcon_cfb16 : &fbcon_banshee16; disp->dispsw_data = info->fbcon_cmap.cfb16; if (nohwcursor) fbcon_banshee16.cursor = NULL; break; #endif #ifdef FBCON_HAS_CFB24 case 24: - info->dispsw = noaccel ? fbcon_cfb24 : fbcon_banshee24; - disp->dispsw = &info->dispsw; + disp->dispsw = noaccel ? &fbcon_cfb24 : &fbcon_banshee24; disp->dispsw_data = info->fbcon_cmap.cfb24; if (nohwcursor) fbcon_banshee24.cursor = NULL; break; #endif #ifdef FBCON_HAS_CFB32 case 32: - info->dispsw = noaccel ? fbcon_cfb32 : fbcon_banshee32; - disp->dispsw = &info->dispsw; + disp->dispsw = noaccel ? &fbcon_cfb32 : &fbcon_banshee32; disp->dispsw_data = info->fbcon_cmap.cfb32; if (nohwcursor) fbcon_banshee32.cursor = NULL; break; #endif default: - info->dispsw = fbcon_dummy; - disp->dispsw = &info->dispsw; + disp->dispsw = &fbcon_dummy; } } @@ -1735,7 +1729,7 @@ static int tdfxfb_set_var(struct fb_var_screeninfo *var, display->can_soft_blank = 1; display->inverse = inverse; accel = var->accel_flags & FB_ACCELF_TEXT; - tdfxfb_set_disp(display, info, par.bpp, accel); + tdfxfb_set_dispsw(display, info, par.bpp, accel); if(nopan) display->scrollmode = SCROLL_YREDRAW; @@ -2083,10 +2077,10 @@ static int tdfxfb_switch_con(int con, info->cursor.redraw=1; - tdfxfb_set_disp(&fb_display[con], - info, - par.bpp, - par.accel_flags & FB_ACCELF_TEXT); + tdfxfb_set_dispsw(&fb_display[con], + info, + par.bpp, + par.accel_flags & FB_ACCELF_TEXT); tdfxfb_install_cmap(&fb_display[con], fb); tdfxfb_updatevar(con, fb); diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c index e48c0f458..6268b1766 100644 --- a/drivers/video/vgacon.c +++ b/drivers/video/vgacon.c @@ -11,7 +11,7 @@ * 1995 Jay Estabrook * * User definable mapping table and font loading by Eugene G. Crosser, - * <crosser@pccross.msk.su> + * <crosser@average.org> * * Improved loadable font/UTF-8 support by H. Peter Anvin * Feb-Sep 1995 <peter.anvin@linux.org> |