xref: /openbmc/linux/drivers/video/fbdev/core/svgalib.c (revision 46f12960)
119757fc8STomi Valkeinen /*
219757fc8STomi Valkeinen  * Common utility functions for VGA-based graphics cards.
319757fc8STomi Valkeinen  *
419757fc8STomi Valkeinen  * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
519757fc8STomi Valkeinen  *
619757fc8STomi Valkeinen  * This file is subject to the terms and conditions of the GNU General Public
719757fc8STomi Valkeinen  * License.  See the file COPYING in the main directory of this archive for
819757fc8STomi Valkeinen  * more details.
919757fc8STomi Valkeinen  *
1019757fc8STomi Valkeinen  * Some parts are based on David Boucher's viafb (http://davesdomain.org.uk/viafb/)
1119757fc8STomi Valkeinen  */
1219757fc8STomi Valkeinen 
1319757fc8STomi Valkeinen #include <linux/module.h>
1419757fc8STomi Valkeinen #include <linux/kernel.h>
1519757fc8STomi Valkeinen #include <linux/string.h>
1619757fc8STomi Valkeinen #include <linux/fb.h>
17*46f12960SAndy Shevchenko #include <linux/math.h>
1819757fc8STomi Valkeinen #include <linux/svga.h>
1919757fc8STomi Valkeinen #include <asm/types.h>
2019757fc8STomi Valkeinen #include <asm/io.h>
2119757fc8STomi Valkeinen 
2219757fc8STomi Valkeinen 
2319757fc8STomi Valkeinen /* Write a CRT register value spread across multiple registers */
svga_wcrt_multi(void __iomem * regbase,const struct vga_regset * regset,u32 value)2419757fc8STomi Valkeinen void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
2519757fc8STomi Valkeinen {
2619757fc8STomi Valkeinen 	u8 regval, bitval, bitnum;
2719757fc8STomi Valkeinen 
2819757fc8STomi Valkeinen 	while (regset->regnum != VGA_REGSET_END_VAL) {
2919757fc8STomi Valkeinen 		regval = vga_rcrt(regbase, regset->regnum);
3019757fc8STomi Valkeinen 		bitnum = regset->lowbit;
3119757fc8STomi Valkeinen 		while (bitnum <= regset->highbit) {
3219757fc8STomi Valkeinen 			bitval = 1 << bitnum;
3319757fc8STomi Valkeinen 			regval = regval & ~bitval;
3419757fc8STomi Valkeinen 			if (value & 1) regval = regval | bitval;
3519757fc8STomi Valkeinen 			bitnum ++;
3619757fc8STomi Valkeinen 			value = value >> 1;
3719757fc8STomi Valkeinen 		}
3819757fc8STomi Valkeinen 		vga_wcrt(regbase, regset->regnum, regval);
3919757fc8STomi Valkeinen 		regset ++;
4019757fc8STomi Valkeinen 	}
4119757fc8STomi Valkeinen }
4219757fc8STomi Valkeinen 
4319757fc8STomi Valkeinen /* Write a sequencer register value spread across multiple registers */
svga_wseq_multi(void __iomem * regbase,const struct vga_regset * regset,u32 value)4419757fc8STomi Valkeinen void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
4519757fc8STomi Valkeinen {
4619757fc8STomi Valkeinen 	u8 regval, bitval, bitnum;
4719757fc8STomi Valkeinen 
4819757fc8STomi Valkeinen 	while (regset->regnum != VGA_REGSET_END_VAL) {
4919757fc8STomi Valkeinen 		regval = vga_rseq(regbase, regset->regnum);
5019757fc8STomi Valkeinen 		bitnum = regset->lowbit;
5119757fc8STomi Valkeinen 		while (bitnum <= regset->highbit) {
5219757fc8STomi Valkeinen 			bitval = 1 << bitnum;
5319757fc8STomi Valkeinen 			regval = regval & ~bitval;
5419757fc8STomi Valkeinen 			if (value & 1) regval = regval | bitval;
5519757fc8STomi Valkeinen 			bitnum ++;
5619757fc8STomi Valkeinen 			value = value >> 1;
5719757fc8STomi Valkeinen 		}
5819757fc8STomi Valkeinen 		vga_wseq(regbase, regset->regnum, regval);
5919757fc8STomi Valkeinen 		regset ++;
6019757fc8STomi Valkeinen 	}
6119757fc8STomi Valkeinen }
6219757fc8STomi Valkeinen 
svga_regset_size(const struct vga_regset * regset)6319757fc8STomi Valkeinen static unsigned int svga_regset_size(const struct vga_regset *regset)
6419757fc8STomi Valkeinen {
6519757fc8STomi Valkeinen 	u8 count = 0;
6619757fc8STomi Valkeinen 
6719757fc8STomi Valkeinen 	while (regset->regnum != VGA_REGSET_END_VAL) {
6819757fc8STomi Valkeinen 		count += regset->highbit - regset->lowbit + 1;
6919757fc8STomi Valkeinen 		regset ++;
7019757fc8STomi Valkeinen 	}
7119757fc8STomi Valkeinen 	return 1 << count;
7219757fc8STomi Valkeinen }
7319757fc8STomi Valkeinen 
7419757fc8STomi Valkeinen 
7519757fc8STomi Valkeinen /* ------------------------------------------------------------------------- */
7619757fc8STomi Valkeinen 
7719757fc8STomi Valkeinen 
7819757fc8STomi Valkeinen /* Set graphics controller registers to sane values */
svga_set_default_gfx_regs(void __iomem * regbase)7919757fc8STomi Valkeinen void svga_set_default_gfx_regs(void __iomem *regbase)
8019757fc8STomi Valkeinen {
8119757fc8STomi Valkeinen 	/* All standard GFX registers (GR00 - GR08) */
8219757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0x00);
8319757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0x00);
8419757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0x00);
8519757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0x00);
8619757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0x00);
8719757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_MODE, 0x00);
8819757fc8STomi Valkeinen /*	vga_wgfx(regbase, VGA_GFX_MODE, 0x20); */
8919757fc8STomi Valkeinen /*	vga_wgfx(regbase, VGA_GFX_MODE, 0x40); */
9019757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_MISC, 0x05);
9119757fc8STomi Valkeinen /*	vga_wgfx(regbase, VGA_GFX_MISC, 0x01); */
9219757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x0F);
9319757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_BIT_MASK, 0xFF);
9419757fc8STomi Valkeinen }
9519757fc8STomi Valkeinen 
9619757fc8STomi Valkeinen /* Set attribute controller registers to sane values */
svga_set_default_atc_regs(void __iomem * regbase)9719757fc8STomi Valkeinen void svga_set_default_atc_regs(void __iomem *regbase)
9819757fc8STomi Valkeinen {
9919757fc8STomi Valkeinen 	u8 count;
10019757fc8STomi Valkeinen 
10119757fc8STomi Valkeinen 	vga_r(regbase, 0x3DA);
10219757fc8STomi Valkeinen 	vga_w(regbase, VGA_ATT_W, 0x00);
10319757fc8STomi Valkeinen 
10419757fc8STomi Valkeinen 	/* All standard ATC registers (AR00 - AR14) */
10519757fc8STomi Valkeinen 	for (count = 0; count <= 0xF; count ++)
10619757fc8STomi Valkeinen 		svga_wattr(regbase, count, count);
10719757fc8STomi Valkeinen 
10819757fc8STomi Valkeinen 	svga_wattr(regbase, VGA_ATC_MODE, 0x01);
10919757fc8STomi Valkeinen /*	svga_wattr(regbase, VGA_ATC_MODE, 0x41); */
11019757fc8STomi Valkeinen 	svga_wattr(regbase, VGA_ATC_OVERSCAN, 0x00);
11119757fc8STomi Valkeinen 	svga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 0x0F);
11219757fc8STomi Valkeinen 	svga_wattr(regbase, VGA_ATC_PEL, 0x00);
11319757fc8STomi Valkeinen 	svga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0x00);
11419757fc8STomi Valkeinen 
11519757fc8STomi Valkeinen 	vga_r(regbase, 0x3DA);
11619757fc8STomi Valkeinen 	vga_w(regbase, VGA_ATT_W, 0x20);
11719757fc8STomi Valkeinen }
11819757fc8STomi Valkeinen 
11919757fc8STomi Valkeinen /* Set sequencer registers to sane values */
svga_set_default_seq_regs(void __iomem * regbase)12019757fc8STomi Valkeinen void svga_set_default_seq_regs(void __iomem *regbase)
12119757fc8STomi Valkeinen {
12219757fc8STomi Valkeinen 	/* Standard sequencer registers (SR01 - SR04), SR00 is not set */
12319757fc8STomi Valkeinen 	vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS);
12419757fc8STomi Valkeinen 	vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES);
12519757fc8STomi Valkeinen 	vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
12619757fc8STomi Valkeinen /*	vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */
12719757fc8STomi Valkeinen 	vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE);
12819757fc8STomi Valkeinen }
12919757fc8STomi Valkeinen 
13019757fc8STomi Valkeinen /* Set CRTC registers to sane values */
svga_set_default_crt_regs(void __iomem * regbase)13119757fc8STomi Valkeinen void svga_set_default_crt_regs(void __iomem *regbase)
13219757fc8STomi Valkeinen {
13319757fc8STomi Valkeinen 	/* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */
13419757fc8STomi Valkeinen 	svga_wcrt_mask(regbase, 0x03, 0x80, 0x80);	/* Enable vertical retrace EVRA */
13519757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
13619757fc8STomi Valkeinen 	svga_wcrt_mask(regbase, VGA_CRTC_MAX_SCAN, 0, 0x1F);
13719757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);
13819757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_MODE, 0xE3);
13919757fc8STomi Valkeinen }
14019757fc8STomi Valkeinen 
svga_set_textmode_vga_regs(void __iomem * regbase)14119757fc8STomi Valkeinen void svga_set_textmode_vga_regs(void __iomem *regbase)
14219757fc8STomi Valkeinen {
14319757fc8STomi Valkeinen 	/* svga_wseq_mask(regbase, 0x1, 0x00, 0x01); */   /* Switch 8/9 pixel per char */
14419757fc8STomi Valkeinen 	vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM);
14519757fc8STomi Valkeinen 	vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x03);
14619757fc8STomi Valkeinen 
14719757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */
14819757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0x1f);
14919757fc8STomi Valkeinen 	svga_wcrt_mask(regbase, VGA_CRTC_MODE, 0x23, 0x7f);
15019757fc8STomi Valkeinen 
15119757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0x0d);
15219757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 0x0e);
15319757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0x00);
15419757fc8STomi Valkeinen 	vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0x00);
15519757fc8STomi Valkeinen 
15619757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_MODE, 0x10); /* Odd/even memory mode */
15719757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_MISC, 0x0E); /* Misc graphics register - text mode enable */
15819757fc8STomi Valkeinen 	vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x00);
15919757fc8STomi Valkeinen 
16019757fc8STomi Valkeinen 	vga_r(regbase, 0x3DA);
16119757fc8STomi Valkeinen 	vga_w(regbase, VGA_ATT_W, 0x00);
16219757fc8STomi Valkeinen 
16319757fc8STomi Valkeinen 	svga_wattr(regbase, 0x10, 0x0C);			/* Attribute Mode Control Register - text mode, blinking and line graphics */
16419757fc8STomi Valkeinen 	svga_wattr(regbase, 0x13, 0x08);			/* Horizontal Pixel Panning Register  */
16519757fc8STomi Valkeinen 
16619757fc8STomi Valkeinen 	vga_r(regbase, 0x3DA);
16719757fc8STomi Valkeinen 	vga_w(regbase, VGA_ATT_W, 0x20);
16819757fc8STomi Valkeinen }
16919757fc8STomi Valkeinen 
17019757fc8STomi Valkeinen #if 0
17119757fc8STomi Valkeinen void svga_dump_var(struct fb_var_screeninfo *var, int node)
17219757fc8STomi Valkeinen {
17319757fc8STomi Valkeinen 	pr_debug("fb%d: var.vmode         : 0x%X\n", node, var->vmode);
17419757fc8STomi Valkeinen 	pr_debug("fb%d: var.xres          : %d\n", node, var->xres);
17519757fc8STomi Valkeinen 	pr_debug("fb%d: var.yres          : %d\n", node, var->yres);
17619757fc8STomi Valkeinen 	pr_debug("fb%d: var.bits_per_pixel: %d\n", node, var->bits_per_pixel);
17719757fc8STomi Valkeinen 	pr_debug("fb%d: var.xres_virtual  : %d\n", node, var->xres_virtual);
17819757fc8STomi Valkeinen 	pr_debug("fb%d: var.yres_virtual  : %d\n", node, var->yres_virtual);
17919757fc8STomi Valkeinen 	pr_debug("fb%d: var.left_margin   : %d\n", node, var->left_margin);
18019757fc8STomi Valkeinen 	pr_debug("fb%d: var.right_margin  : %d\n", node, var->right_margin);
18119757fc8STomi Valkeinen 	pr_debug("fb%d: var.upper_margin  : %d\n", node, var->upper_margin);
18219757fc8STomi Valkeinen 	pr_debug("fb%d: var.lower_margin  : %d\n", node, var->lower_margin);
18319757fc8STomi Valkeinen 	pr_debug("fb%d: var.hsync_len     : %d\n", node, var->hsync_len);
18419757fc8STomi Valkeinen 	pr_debug("fb%d: var.vsync_len     : %d\n", node, var->vsync_len);
18519757fc8STomi Valkeinen 	pr_debug("fb%d: var.sync          : 0x%X\n", node, var->sync);
18619757fc8STomi Valkeinen 	pr_debug("fb%d: var.pixclock      : %d\n\n", node, var->pixclock);
18719757fc8STomi Valkeinen }
18819757fc8STomi Valkeinen #endif  /*  0  */
18919757fc8STomi Valkeinen 
19019757fc8STomi Valkeinen 
19119757fc8STomi Valkeinen /* ------------------------------------------------------------------------- */
19219757fc8STomi Valkeinen 
19319757fc8STomi Valkeinen 
svga_settile(struct fb_info * info,struct fb_tilemap * map)19419757fc8STomi Valkeinen void svga_settile(struct fb_info *info, struct fb_tilemap *map)
19519757fc8STomi Valkeinen {
19619757fc8STomi Valkeinen 	const u8 *font = map->data;
19719757fc8STomi Valkeinen 	u8 __iomem *fb = (u8 __iomem *)info->screen_base;
19819757fc8STomi Valkeinen 	int i, c;
19919757fc8STomi Valkeinen 
20019757fc8STomi Valkeinen 	if ((map->width != 8) || (map->height != 16) ||
20119757fc8STomi Valkeinen 	    (map->depth != 1) || (map->length != 256)) {
20219757fc8STomi Valkeinen 		fb_err(info, "unsupported font parameters: width %d, height %d, depth %d, length %d\n",
20319757fc8STomi Valkeinen 		       map->width, map->height, map->depth, map->length);
20419757fc8STomi Valkeinen 		return;
20519757fc8STomi Valkeinen 	}
20619757fc8STomi Valkeinen 
20719757fc8STomi Valkeinen 	fb += 2;
20819757fc8STomi Valkeinen 	for (c = 0; c < map->length; c++) {
20919757fc8STomi Valkeinen 		for (i = 0; i < map->height; i++) {
21019757fc8STomi Valkeinen 			fb_writeb(font[i], fb + i * 4);
21119757fc8STomi Valkeinen //			fb[i * 4] = font[i];
21219757fc8STomi Valkeinen 		}
21319757fc8STomi Valkeinen 		fb += 128;
21419757fc8STomi Valkeinen 		font += map->height;
21519757fc8STomi Valkeinen 	}
21619757fc8STomi Valkeinen }
21719757fc8STomi Valkeinen 
21819757fc8STomi Valkeinen /* Copy area in text (tileblit) mode */
svga_tilecopy(struct fb_info * info,struct fb_tilearea * area)21919757fc8STomi Valkeinen void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)
22019757fc8STomi Valkeinen {
22119757fc8STomi Valkeinen 	int dx, dy;
22219757fc8STomi Valkeinen 	/*  colstride is halved in this function because u16 are used */
22319757fc8STomi Valkeinen 	int colstride = 1 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
22419757fc8STomi Valkeinen 	int rowstride = colstride * (info->var.xres_virtual / 8);
22519757fc8STomi Valkeinen 	u16 __iomem *fb = (u16 __iomem *) info->screen_base;
22619757fc8STomi Valkeinen 	u16 __iomem *src, *dst;
22719757fc8STomi Valkeinen 
22819757fc8STomi Valkeinen 	if ((area->sy > area->dy) ||
22919757fc8STomi Valkeinen 	    ((area->sy == area->dy) && (area->sx > area->dx))) {
23019757fc8STomi Valkeinen 		src = fb + area->sx * colstride + area->sy * rowstride;
23119757fc8STomi Valkeinen 		dst = fb + area->dx * colstride + area->dy * rowstride;
23219757fc8STomi Valkeinen 	    } else {
23319757fc8STomi Valkeinen 		src = fb + (area->sx + area->width - 1) * colstride
23419757fc8STomi Valkeinen 			 + (area->sy + area->height - 1) * rowstride;
23519757fc8STomi Valkeinen 		dst = fb + (area->dx + area->width - 1) * colstride
23619757fc8STomi Valkeinen 			 + (area->dy + area->height - 1) * rowstride;
23719757fc8STomi Valkeinen 
23819757fc8STomi Valkeinen 		colstride = -colstride;
23919757fc8STomi Valkeinen 		rowstride = -rowstride;
24019757fc8STomi Valkeinen 	    }
24119757fc8STomi Valkeinen 
24219757fc8STomi Valkeinen 	for (dy = 0; dy < area->height; dy++) {
24319757fc8STomi Valkeinen 		u16 __iomem *src2 = src;
24419757fc8STomi Valkeinen 		u16 __iomem *dst2 = dst;
24519757fc8STomi Valkeinen 		for (dx = 0; dx < area->width; dx++) {
24619757fc8STomi Valkeinen 			fb_writew(fb_readw(src2), dst2);
24719757fc8STomi Valkeinen //			*dst2 = *src2;
24819757fc8STomi Valkeinen 			src2 += colstride;
24919757fc8STomi Valkeinen 			dst2 += colstride;
25019757fc8STomi Valkeinen 		}
25119757fc8STomi Valkeinen 		src += rowstride;
25219757fc8STomi Valkeinen 		dst += rowstride;
25319757fc8STomi Valkeinen 	}
25419757fc8STomi Valkeinen }
25519757fc8STomi Valkeinen 
25619757fc8STomi Valkeinen /* Fill area in text (tileblit) mode */
svga_tilefill(struct fb_info * info,struct fb_tilerect * rect)25719757fc8STomi Valkeinen void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect)
25819757fc8STomi Valkeinen {
25919757fc8STomi Valkeinen 	int dx, dy;
26019757fc8STomi Valkeinen 	int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
26119757fc8STomi Valkeinen 	int rowstride = colstride * (info->var.xres_virtual / 8);
26219757fc8STomi Valkeinen 	int attr = (0x0F & rect->bg) << 4 | (0x0F & rect->fg);
26319757fc8STomi Valkeinen 	u8 __iomem *fb = (u8 __iomem *)info->screen_base;
26419757fc8STomi Valkeinen 	fb += rect->sx * colstride + rect->sy * rowstride;
26519757fc8STomi Valkeinen 
26619757fc8STomi Valkeinen 	for (dy = 0; dy < rect->height; dy++) {
26719757fc8STomi Valkeinen 		u8 __iomem *fb2 = fb;
26819757fc8STomi Valkeinen 		for (dx = 0; dx < rect->width; dx++) {
26919757fc8STomi Valkeinen 			fb_writeb(rect->index, fb2);
27019757fc8STomi Valkeinen 			fb_writeb(attr, fb2 + 1);
27119757fc8STomi Valkeinen 			fb2 += colstride;
27219757fc8STomi Valkeinen 		}
27319757fc8STomi Valkeinen 		fb += rowstride;
27419757fc8STomi Valkeinen 	}
27519757fc8STomi Valkeinen }
27619757fc8STomi Valkeinen 
27719757fc8STomi Valkeinen /* Write text in text (tileblit) mode */
svga_tileblit(struct fb_info * info,struct fb_tileblit * blit)27819757fc8STomi Valkeinen void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)
27919757fc8STomi Valkeinen {
28019757fc8STomi Valkeinen 	int dx, dy, i;
28119757fc8STomi Valkeinen 	int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
28219757fc8STomi Valkeinen 	int rowstride = colstride * (info->var.xres_virtual / 8);
28319757fc8STomi Valkeinen 	int attr = (0x0F & blit->bg) << 4 | (0x0F & blit->fg);
28419757fc8STomi Valkeinen 	u8 __iomem *fb = (u8 __iomem *)info->screen_base;
28519757fc8STomi Valkeinen 	fb += blit->sx * colstride + blit->sy * rowstride;
28619757fc8STomi Valkeinen 
28719757fc8STomi Valkeinen 	i=0;
28819757fc8STomi Valkeinen 	for (dy=0; dy < blit->height; dy ++) {
28919757fc8STomi Valkeinen 		u8 __iomem *fb2 = fb;
29019757fc8STomi Valkeinen 		for (dx = 0; dx < blit->width; dx ++) {
29119757fc8STomi Valkeinen 			fb_writeb(blit->indices[i], fb2);
29219757fc8STomi Valkeinen 			fb_writeb(attr, fb2 + 1);
29319757fc8STomi Valkeinen 			fb2 += colstride;
29419757fc8STomi Valkeinen 			i ++;
29519757fc8STomi Valkeinen 			if (i == blit->length) return;
29619757fc8STomi Valkeinen 		}
29719757fc8STomi Valkeinen 		fb += rowstride;
29819757fc8STomi Valkeinen 	}
29919757fc8STomi Valkeinen 
30019757fc8STomi Valkeinen }
30119757fc8STomi Valkeinen 
30219757fc8STomi Valkeinen /* Set cursor in text (tileblit) mode */
svga_tilecursor(void __iomem * regbase,struct fb_info * info,struct fb_tilecursor * cursor)30319757fc8STomi Valkeinen void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tilecursor *cursor)
30419757fc8STomi Valkeinen {
30519757fc8STomi Valkeinen 	u8 cs = 0x0d;
30619757fc8STomi Valkeinen 	u8 ce = 0x0e;
30719757fc8STomi Valkeinen 	u16 pos =  cursor->sx + (info->var.xoffset /  8)
30819757fc8STomi Valkeinen 		+ (cursor->sy + (info->var.yoffset / 16))
30919757fc8STomi Valkeinen 		   * (info->var.xres_virtual / 8);
31019757fc8STomi Valkeinen 
31119757fc8STomi Valkeinen 	if (! cursor -> mode)
31219757fc8STomi Valkeinen 		return;
31319757fc8STomi Valkeinen 
31419757fc8STomi Valkeinen 	svga_wcrt_mask(regbase, 0x0A, 0x20, 0x20); /* disable cursor */
31519757fc8STomi Valkeinen 
31619757fc8STomi Valkeinen 	if (cursor -> shape == FB_TILE_CURSOR_NONE)
31719757fc8STomi Valkeinen 		return;
31819757fc8STomi Valkeinen 
31919757fc8STomi Valkeinen 	switch (cursor -> shape) {
32019757fc8STomi Valkeinen 	case FB_TILE_CURSOR_UNDERLINE:
32119757fc8STomi Valkeinen 		cs = 0x0d;
32219757fc8STomi Valkeinen 		break;
32319757fc8STomi Valkeinen 	case FB_TILE_CURSOR_LOWER_THIRD:
32419757fc8STomi Valkeinen 		cs = 0x09;
32519757fc8STomi Valkeinen 		break;
32619757fc8STomi Valkeinen 	case FB_TILE_CURSOR_LOWER_HALF:
32719757fc8STomi Valkeinen 		cs = 0x07;
32819757fc8STomi Valkeinen 		break;
32919757fc8STomi Valkeinen 	case FB_TILE_CURSOR_TWO_THIRDS:
33019757fc8STomi Valkeinen 		cs = 0x05;
33119757fc8STomi Valkeinen 		break;
33219757fc8STomi Valkeinen 	case FB_TILE_CURSOR_BLOCK:
33319757fc8STomi Valkeinen 		cs = 0x01;
33419757fc8STomi Valkeinen 		break;
33519757fc8STomi Valkeinen 	}
33619757fc8STomi Valkeinen 
33719757fc8STomi Valkeinen 	/* set cursor position */
33819757fc8STomi Valkeinen 	vga_wcrt(regbase, 0x0E, pos >> 8);
33919757fc8STomi Valkeinen 	vga_wcrt(regbase, 0x0F, pos & 0xFF);
34019757fc8STomi Valkeinen 
34119757fc8STomi Valkeinen 	vga_wcrt(regbase, 0x0B, ce); /* set cursor end */
34219757fc8STomi Valkeinen 	vga_wcrt(regbase, 0x0A, cs); /* set cursor start and enable it */
34319757fc8STomi Valkeinen }
34419757fc8STomi Valkeinen 
svga_get_tilemax(struct fb_info * info)34519757fc8STomi Valkeinen int svga_get_tilemax(struct fb_info *info)
34619757fc8STomi Valkeinen {
34719757fc8STomi Valkeinen 	return 256;
34819757fc8STomi Valkeinen }
34919757fc8STomi Valkeinen 
35019757fc8STomi Valkeinen /* Get capabilities of accelerator based on the mode */
35119757fc8STomi Valkeinen 
svga_get_caps(struct fb_info * info,struct fb_blit_caps * caps,struct fb_var_screeninfo * var)35219757fc8STomi Valkeinen void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
35319757fc8STomi Valkeinen 		   struct fb_var_screeninfo *var)
35419757fc8STomi Valkeinen {
35519757fc8STomi Valkeinen 	if (var->bits_per_pixel == 0) {
35619757fc8STomi Valkeinen 		/* can only support 256 8x16 bitmap */
35719757fc8STomi Valkeinen 		caps->x = 1 << (8 - 1);
35819757fc8STomi Valkeinen 		caps->y = 1 << (16 - 1);
35919757fc8STomi Valkeinen 		caps->len = 256;
36019757fc8STomi Valkeinen 	} else {
36119757fc8STomi Valkeinen 		caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
36219757fc8STomi Valkeinen 		caps->y = ~(u32)0;
36319757fc8STomi Valkeinen 		caps->len = ~(u32)0;
36419757fc8STomi Valkeinen 	}
36519757fc8STomi Valkeinen }
36619757fc8STomi Valkeinen EXPORT_SYMBOL(svga_get_caps);
36719757fc8STomi Valkeinen 
36819757fc8STomi Valkeinen /* ------------------------------------------------------------------------- */
36919757fc8STomi Valkeinen 
37019757fc8STomi Valkeinen 
37119757fc8STomi Valkeinen /*
37219757fc8STomi Valkeinen  *  Compute PLL settings (M, N, R)
37319757fc8STomi Valkeinen  *  F_VCO = (F_BASE * M) / N
37419757fc8STomi Valkeinen  *  F_OUT = F_VCO / (2^R)
37519757fc8STomi Valkeinen  */
svga_compute_pll(const struct svga_pll * pll,u32 f_wanted,u16 * m,u16 * n,u16 * r,int node)37619757fc8STomi Valkeinen int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node)
37719757fc8STomi Valkeinen {
37819757fc8STomi Valkeinen 	u16 am, an, ar;
37919757fc8STomi Valkeinen 	u32 f_vco, f_current, delta_current, delta_best;
38019757fc8STomi Valkeinen 
38119757fc8STomi Valkeinen 	pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int) f_wanted);
38219757fc8STomi Valkeinen 
38319757fc8STomi Valkeinen 	ar = pll->r_max;
38419757fc8STomi Valkeinen 	f_vco = f_wanted << ar;
38519757fc8STomi Valkeinen 
38619757fc8STomi Valkeinen 	/* overflow check */
38719757fc8STomi Valkeinen 	if ((f_vco >> ar) != f_wanted)
38819757fc8STomi Valkeinen 		return -EINVAL;
38919757fc8STomi Valkeinen 
39019757fc8STomi Valkeinen 	/* It is usually better to have greater VCO clock
39119757fc8STomi Valkeinen 	   because of better frequency stability.
39219757fc8STomi Valkeinen 	   So first try r_max, then r smaller. */
39319757fc8STomi Valkeinen 	while ((ar > pll->r_min) && (f_vco > pll->f_vco_max)) {
39419757fc8STomi Valkeinen 		ar--;
39519757fc8STomi Valkeinen 		f_vco = f_vco >> 1;
39619757fc8STomi Valkeinen 	}
39719757fc8STomi Valkeinen 
39819757fc8STomi Valkeinen 	/* VCO bounds check */
39919757fc8STomi Valkeinen 	if ((f_vco < pll->f_vco_min) || (f_vco > pll->f_vco_max))
40019757fc8STomi Valkeinen 		return -EINVAL;
40119757fc8STomi Valkeinen 
40219757fc8STomi Valkeinen 	delta_best = 0xFFFFFFFF;
40319757fc8STomi Valkeinen 	*m = 0;
40419757fc8STomi Valkeinen 	*n = 0;
40519757fc8STomi Valkeinen 	*r = ar;
40619757fc8STomi Valkeinen 
40719757fc8STomi Valkeinen 	am = pll->m_min;
40819757fc8STomi Valkeinen 	an = pll->n_min;
40919757fc8STomi Valkeinen 
41019757fc8STomi Valkeinen 	while ((am <= pll->m_max) && (an <= pll->n_max)) {
41119757fc8STomi Valkeinen 		f_current = (pll->f_base * am) / an;
41219757fc8STomi Valkeinen 		delta_current = abs_diff (f_current, f_vco);
41319757fc8STomi Valkeinen 
41419757fc8STomi Valkeinen 		if (delta_current < delta_best) {
41519757fc8STomi Valkeinen 			delta_best = delta_current;
41619757fc8STomi Valkeinen 			*m = am;
41719757fc8STomi Valkeinen 			*n = an;
41819757fc8STomi Valkeinen 		}
41919757fc8STomi Valkeinen 
42019757fc8STomi Valkeinen 		if (f_current <= f_vco) {
42119757fc8STomi Valkeinen 			am ++;
42219757fc8STomi Valkeinen 		} else {
42319757fc8STomi Valkeinen 			an ++;
42419757fc8STomi Valkeinen 		}
42519757fc8STomi Valkeinen 	}
42619757fc8STomi Valkeinen 
42719757fc8STomi Valkeinen 	f_current = (pll->f_base * *m) / *n;
42819757fc8STomi Valkeinen 	pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int) (f_current >> ar), (int) f_current);
42919757fc8STomi Valkeinen 	pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int) *m, (unsigned int) *n, (unsigned int) *r);
43019757fc8STomi Valkeinen 	return 0;
43119757fc8STomi Valkeinen }
43219757fc8STomi Valkeinen 
43319757fc8STomi Valkeinen 
43419757fc8STomi Valkeinen /* ------------------------------------------------------------------------- */
43519757fc8STomi Valkeinen 
43619757fc8STomi Valkeinen 
43719757fc8STomi Valkeinen /* Check CRT timing values */
svga_check_timings(const struct svga_timing_regs * tm,struct fb_var_screeninfo * var,int node)43819757fc8STomi Valkeinen int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node)
43919757fc8STomi Valkeinen {
44019757fc8STomi Valkeinen 	u32 value;
44119757fc8STomi Valkeinen 
44219757fc8STomi Valkeinen 	var->xres         = (var->xres+7)&~7;
44319757fc8STomi Valkeinen 	var->left_margin  = (var->left_margin+7)&~7;
44419757fc8STomi Valkeinen 	var->right_margin = (var->right_margin+7)&~7;
44519757fc8STomi Valkeinen 	var->hsync_len    = (var->hsync_len+7)&~7;
44619757fc8STomi Valkeinen 
44719757fc8STomi Valkeinen 	/* Check horizontal total */
44819757fc8STomi Valkeinen 	value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
44919757fc8STomi Valkeinen 	if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs))
45019757fc8STomi Valkeinen 		return -EINVAL;
45119757fc8STomi Valkeinen 
45219757fc8STomi Valkeinen 	/* Check horizontal display and blank start */
45319757fc8STomi Valkeinen 	value = var->xres;
45419757fc8STomi Valkeinen 	if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs))
45519757fc8STomi Valkeinen 		return -EINVAL;
45619757fc8STomi Valkeinen 	if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs))
45719757fc8STomi Valkeinen 		return -EINVAL;
45819757fc8STomi Valkeinen 
45919757fc8STomi Valkeinen 	/* Check horizontal sync start */
46019757fc8STomi Valkeinen 	value = var->xres + var->right_margin;
46119757fc8STomi Valkeinen 	if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs))
46219757fc8STomi Valkeinen 		return -EINVAL;
46319757fc8STomi Valkeinen 
46419757fc8STomi Valkeinen 	/* Check horizontal blank end (or length) */
46519757fc8STomi Valkeinen 	value = var->left_margin + var->right_margin + var->hsync_len;
46619757fc8STomi Valkeinen 	if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs)))
46719757fc8STomi Valkeinen 		return -EINVAL;
46819757fc8STomi Valkeinen 
46919757fc8STomi Valkeinen 	/* Check horizontal sync end (or length) */
47019757fc8STomi Valkeinen 	value = var->hsync_len;
47119757fc8STomi Valkeinen 	if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs)))
47219757fc8STomi Valkeinen 		return -EINVAL;
47319757fc8STomi Valkeinen 
47419757fc8STomi Valkeinen 	/* Check vertical total */
47519757fc8STomi Valkeinen 	value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
47619757fc8STomi Valkeinen 	if ((value - 1) >= svga_regset_size(tm->v_total_regs))
47719757fc8STomi Valkeinen 		return -EINVAL;
47819757fc8STomi Valkeinen 
47919757fc8STomi Valkeinen 	/* Check vertical display and blank start */
48019757fc8STomi Valkeinen 	value = var->yres;
48119757fc8STomi Valkeinen 	if ((value - 1) >= svga_regset_size(tm->v_display_regs))
48219757fc8STomi Valkeinen 		return -EINVAL;
48319757fc8STomi Valkeinen 	if ((value - 1) >= svga_regset_size(tm->v_blank_start_regs))
48419757fc8STomi Valkeinen 		return -EINVAL;
48519757fc8STomi Valkeinen 
48619757fc8STomi Valkeinen 	/* Check vertical sync start */
48719757fc8STomi Valkeinen 	value = var->yres + var->lower_margin;
48819757fc8STomi Valkeinen 	if ((value - 1) >= svga_regset_size(tm->v_sync_start_regs))
48919757fc8STomi Valkeinen 		return -EINVAL;
49019757fc8STomi Valkeinen 
49119757fc8STomi Valkeinen 	/* Check vertical blank end (or length) */
49219757fc8STomi Valkeinen 	value = var->upper_margin + var->lower_margin + var->vsync_len;
49319757fc8STomi Valkeinen 	if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs)))
49419757fc8STomi Valkeinen 		return -EINVAL;
49519757fc8STomi Valkeinen 
49619757fc8STomi Valkeinen 	/* Check vertical sync end  (or length) */
49719757fc8STomi Valkeinen 	value = var->vsync_len;
49819757fc8STomi Valkeinen 	if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs)))
49919757fc8STomi Valkeinen 		return -EINVAL;
50019757fc8STomi Valkeinen 
50119757fc8STomi Valkeinen 	return 0;
50219757fc8STomi Valkeinen }
50319757fc8STomi Valkeinen 
50419757fc8STomi Valkeinen /* Set CRT timing registers */
svga_set_timings(void __iomem * regbase,const struct svga_timing_regs * tm,struct fb_var_screeninfo * var,u32 hmul,u32 hdiv,u32 vmul,u32 vdiv,u32 hborder,int node)50519757fc8STomi Valkeinen void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm,
50619757fc8STomi Valkeinen 		      struct fb_var_screeninfo *var,
50719757fc8STomi Valkeinen 		      u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node)
50819757fc8STomi Valkeinen {
50919757fc8STomi Valkeinen 	u8 regval;
51019757fc8STomi Valkeinen 	u32 value;
51119757fc8STomi Valkeinen 
51219757fc8STomi Valkeinen 	value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
51319757fc8STomi Valkeinen 	value = (value * hmul) / hdiv;
51419757fc8STomi Valkeinen 	pr_debug("fb%d: horizontal total      : %d\n", node, value);
51519757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->h_total_regs, (value / 8) - 5);
51619757fc8STomi Valkeinen 
51719757fc8STomi Valkeinen 	value = var->xres;
51819757fc8STomi Valkeinen 	value = (value * hmul) / hdiv;
51919757fc8STomi Valkeinen 	pr_debug("fb%d: horizontal display    : %d\n", node, value);
52019757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->h_display_regs, (value / 8) - 1);
52119757fc8STomi Valkeinen 
52219757fc8STomi Valkeinen 	value = var->xres;
52319757fc8STomi Valkeinen 	value = (value * hmul) / hdiv;
52419757fc8STomi Valkeinen 	pr_debug("fb%d: horizontal blank start: %d\n", node, value);
52519757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->h_blank_start_regs, (value / 8) - 1 + hborder);
52619757fc8STomi Valkeinen 
52719757fc8STomi Valkeinen 	value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
52819757fc8STomi Valkeinen 	value = (value * hmul) / hdiv;
52919757fc8STomi Valkeinen 	pr_debug("fb%d: horizontal blank end  : %d\n", node, value);
53019757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->h_blank_end_regs, (value / 8) - 1 - hborder);
53119757fc8STomi Valkeinen 
53219757fc8STomi Valkeinen 	value = var->xres + var->right_margin;
53319757fc8STomi Valkeinen 	value = (value * hmul) / hdiv;
53419757fc8STomi Valkeinen 	pr_debug("fb%d: horizontal sync start : %d\n", node, value);
53519757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->h_sync_start_regs, (value / 8));
53619757fc8STomi Valkeinen 
53719757fc8STomi Valkeinen 	value = var->xres + var->right_margin + var->hsync_len;
53819757fc8STomi Valkeinen 	value = (value * hmul) / hdiv;
53919757fc8STomi Valkeinen 	pr_debug("fb%d: horizontal sync end   : %d\n", node, value);
54019757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->h_sync_end_regs, (value / 8));
54119757fc8STomi Valkeinen 
54219757fc8STomi Valkeinen 	value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
54319757fc8STomi Valkeinen 	value = (value * vmul) / vdiv;
54419757fc8STomi Valkeinen 	pr_debug("fb%d: vertical total        : %d\n", node, value);
54519757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->v_total_regs, value - 2);
54619757fc8STomi Valkeinen 
54719757fc8STomi Valkeinen 	value = var->yres;
54819757fc8STomi Valkeinen 	value = (value * vmul) / vdiv;
54919757fc8STomi Valkeinen 	pr_debug("fb%d: vertical display      : %d\n", node, value);
55019757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->v_display_regs, value - 1);
55119757fc8STomi Valkeinen 
55219757fc8STomi Valkeinen 	value = var->yres;
55319757fc8STomi Valkeinen 	value = (value * vmul) / vdiv;
55419757fc8STomi Valkeinen 	pr_debug("fb%d: vertical blank start  : %d\n", node, value);
55519757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->v_blank_start_regs, value);
55619757fc8STomi Valkeinen 
55719757fc8STomi Valkeinen 	value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
55819757fc8STomi Valkeinen 	value = (value * vmul) / vdiv;
55919757fc8STomi Valkeinen 	pr_debug("fb%d: vertical blank end    : %d\n", node, value);
56019757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->v_blank_end_regs, value - 2);
56119757fc8STomi Valkeinen 
56219757fc8STomi Valkeinen 	value = var->yres + var->lower_margin;
56319757fc8STomi Valkeinen 	value = (value * vmul) / vdiv;
56419757fc8STomi Valkeinen 	pr_debug("fb%d: vertical sync start   : %d\n", node, value);
56519757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->v_sync_start_regs, value);
56619757fc8STomi Valkeinen 
56719757fc8STomi Valkeinen 	value = var->yres + var->lower_margin + var->vsync_len;
56819757fc8STomi Valkeinen 	value = (value * vmul) / vdiv;
56919757fc8STomi Valkeinen 	pr_debug("fb%d: vertical sync end     : %d\n", node, value);
57019757fc8STomi Valkeinen 	svga_wcrt_multi(regbase, tm->v_sync_end_regs, value);
57119757fc8STomi Valkeinen 
57219757fc8STomi Valkeinen 	/* Set horizontal and vertical sync pulse polarity in misc register */
57319757fc8STomi Valkeinen 
57419757fc8STomi Valkeinen 	regval = vga_r(regbase, VGA_MIS_R);
57519757fc8STomi Valkeinen 	if (var->sync & FB_SYNC_HOR_HIGH_ACT) {
57619757fc8STomi Valkeinen 		pr_debug("fb%d: positive horizontal sync\n", node);
57719757fc8STomi Valkeinen 		regval = regval & ~0x80;
57819757fc8STomi Valkeinen 	} else {
57919757fc8STomi Valkeinen 		pr_debug("fb%d: negative horizontal sync\n", node);
58019757fc8STomi Valkeinen 		regval = regval | 0x80;
58119757fc8STomi Valkeinen 	}
58219757fc8STomi Valkeinen 	if (var->sync & FB_SYNC_VERT_HIGH_ACT) {
58319757fc8STomi Valkeinen 		pr_debug("fb%d: positive vertical sync\n", node);
58419757fc8STomi Valkeinen 		regval = regval & ~0x40;
58519757fc8STomi Valkeinen 	} else {
58619757fc8STomi Valkeinen 		pr_debug("fb%d: negative vertical sync\n\n", node);
58719757fc8STomi Valkeinen 		regval = regval | 0x40;
58819757fc8STomi Valkeinen 	}
58919757fc8STomi Valkeinen 	vga_w(regbase, VGA_MIS_W, regval);
59019757fc8STomi Valkeinen }
59119757fc8STomi Valkeinen 
59219757fc8STomi Valkeinen 
59319757fc8STomi Valkeinen /* ------------------------------------------------------------------------- */
59419757fc8STomi Valkeinen 
59519757fc8STomi Valkeinen 
match_format(const struct svga_fb_format * frm,struct fb_var_screeninfo * var)59619757fc8STomi Valkeinen static inline int match_format(const struct svga_fb_format *frm,
59719757fc8STomi Valkeinen 			       struct fb_var_screeninfo *var)
59819757fc8STomi Valkeinen {
59919757fc8STomi Valkeinen 	int i = 0;
60019757fc8STomi Valkeinen 	int stored = -EINVAL;
60119757fc8STomi Valkeinen 
60219757fc8STomi Valkeinen 	while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL)
60319757fc8STomi Valkeinen 	{
60419757fc8STomi Valkeinen 		if ((var->bits_per_pixel == frm->bits_per_pixel) &&
60519757fc8STomi Valkeinen 		    (var->red.length     <= frm->red.length)     &&
60619757fc8STomi Valkeinen 		    (var->green.length   <= frm->green.length)   &&
60719757fc8STomi Valkeinen 		    (var->blue.length    <= frm->blue.length)    &&
60819757fc8STomi Valkeinen 		    (var->transp.length  <= frm->transp.length)  &&
60919757fc8STomi Valkeinen 		    (var->nonstd	 == frm->nonstd))
61019757fc8STomi Valkeinen 			return i;
61119757fc8STomi Valkeinen 		if (var->bits_per_pixel == frm->bits_per_pixel)
61219757fc8STomi Valkeinen 			stored = i;
61319757fc8STomi Valkeinen 		i++;
61419757fc8STomi Valkeinen 		frm++;
61519757fc8STomi Valkeinen 	}
61619757fc8STomi Valkeinen 	return stored;
61719757fc8STomi Valkeinen }
61819757fc8STomi Valkeinen 
svga_match_format(const struct svga_fb_format * frm,struct fb_var_screeninfo * var,struct fb_fix_screeninfo * fix)61919757fc8STomi Valkeinen int svga_match_format(const struct svga_fb_format *frm,
62019757fc8STomi Valkeinen 		      struct fb_var_screeninfo *var,
62119757fc8STomi Valkeinen 		      struct fb_fix_screeninfo *fix)
62219757fc8STomi Valkeinen {
62319757fc8STomi Valkeinen 	int i = match_format(frm, var);
62419757fc8STomi Valkeinen 
62519757fc8STomi Valkeinen 	if (i >= 0) {
62619757fc8STomi Valkeinen 		var->bits_per_pixel = frm[i].bits_per_pixel;
62719757fc8STomi Valkeinen 		var->red            = frm[i].red;
62819757fc8STomi Valkeinen 		var->green          = frm[i].green;
62919757fc8STomi Valkeinen 		var->blue           = frm[i].blue;
63019757fc8STomi Valkeinen 		var->transp         = frm[i].transp;
63119757fc8STomi Valkeinen 		var->nonstd         = frm[i].nonstd;
63219757fc8STomi Valkeinen 		if (fix != NULL) {
63319757fc8STomi Valkeinen 			fix->type      = frm[i].type;
63419757fc8STomi Valkeinen 			fix->type_aux  = frm[i].type_aux;
63519757fc8STomi Valkeinen 			fix->visual    = frm[i].visual;
63619757fc8STomi Valkeinen 			fix->xpanstep  = frm[i].xpanstep;
63719757fc8STomi Valkeinen 		}
63819757fc8STomi Valkeinen 	}
63919757fc8STomi Valkeinen 
64019757fc8STomi Valkeinen 	return i;
64119757fc8STomi Valkeinen }
64219757fc8STomi Valkeinen 
64319757fc8STomi Valkeinen 
64419757fc8STomi Valkeinen EXPORT_SYMBOL(svga_wcrt_multi);
64519757fc8STomi Valkeinen EXPORT_SYMBOL(svga_wseq_multi);
64619757fc8STomi Valkeinen 
64719757fc8STomi Valkeinen EXPORT_SYMBOL(svga_set_default_gfx_regs);
64819757fc8STomi Valkeinen EXPORT_SYMBOL(svga_set_default_atc_regs);
64919757fc8STomi Valkeinen EXPORT_SYMBOL(svga_set_default_seq_regs);
65019757fc8STomi Valkeinen EXPORT_SYMBOL(svga_set_default_crt_regs);
65119757fc8STomi Valkeinen EXPORT_SYMBOL(svga_set_textmode_vga_regs);
65219757fc8STomi Valkeinen 
65319757fc8STomi Valkeinen EXPORT_SYMBOL(svga_settile);
65419757fc8STomi Valkeinen EXPORT_SYMBOL(svga_tilecopy);
65519757fc8STomi Valkeinen EXPORT_SYMBOL(svga_tilefill);
65619757fc8STomi Valkeinen EXPORT_SYMBOL(svga_tileblit);
65719757fc8STomi Valkeinen EXPORT_SYMBOL(svga_tilecursor);
65819757fc8STomi Valkeinen EXPORT_SYMBOL(svga_get_tilemax);
65919757fc8STomi Valkeinen 
66019757fc8STomi Valkeinen EXPORT_SYMBOL(svga_compute_pll);
66119757fc8STomi Valkeinen EXPORT_SYMBOL(svga_check_timings);
66219757fc8STomi Valkeinen EXPORT_SYMBOL(svga_set_timings);
66319757fc8STomi Valkeinen EXPORT_SYMBOL(svga_match_format);
66419757fc8STomi Valkeinen 
66519757fc8STomi Valkeinen MODULE_AUTHOR("Ondrej Zajicek <santiago@crfreenet.org>");
66619757fc8STomi Valkeinen MODULE_DESCRIPTION("Common utility functions for VGA-based graphics cards");
66719757fc8STomi Valkeinen MODULE_LICENSE("GPL");
668