162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SiS 300/540/630[S]/730[S],
462306a36Sopenharmony_ci * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX],
562306a36Sopenharmony_ci * XGI V3XT/V5/V8, Z7
662306a36Sopenharmony_ci * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * 2D acceleration part
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Based on the XFree86/X.org driver which is
1162306a36Sopenharmony_ci *     Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Author: Thomas Winischhofer <thomas@winischhofer.net>
1462306a36Sopenharmony_ci *			(see http://www.winischhofer.net/
1562306a36Sopenharmony_ci *			for more information and updates)
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/fb.h>
2162306a36Sopenharmony_ci#include <linux/ioport.h>
2262306a36Sopenharmony_ci#include <linux/types.h>
2362306a36Sopenharmony_ci#include <asm/io.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "sis.h"
2662306a36Sopenharmony_ci#include "sis_accel.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic const u8 sisALUConv[] =
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci    0x00,       /* dest = 0;            0,      GXclear,        0 */
3162306a36Sopenharmony_ci    0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
3262306a36Sopenharmony_ci    0x44,       /* dest = src & ~dest;  SDna,   GXandReverse,   0x2 */
3362306a36Sopenharmony_ci    0xCC,       /* dest = src;          S,      GXcopy,         0x3 */
3462306a36Sopenharmony_ci    0x22,       /* dest &= ~src;        DSna,   GXandInverted,  0x4 */
3562306a36Sopenharmony_ci    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
3662306a36Sopenharmony_ci    0x66,       /* dest = ^src;         DSx,    GXxor,          0x6 */
3762306a36Sopenharmony_ci    0xEE,       /* dest |= src;         DSo,    GXor,           0x7 */
3862306a36Sopenharmony_ci    0x11,       /* dest = ~src & ~dest; DSon,   GXnor,          0x8 */
3962306a36Sopenharmony_ci    0x99,       /* dest ^= ~src ;       DSxn,   GXequiv,        0x9 */
4062306a36Sopenharmony_ci    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
4162306a36Sopenharmony_ci    0xDD,       /* dest = src|~dest ;   SDno,   GXorReverse,    0xB */
4262306a36Sopenharmony_ci    0x33,       /* dest = ~src;         Sn,     GXcopyInverted, 0xC */
4362306a36Sopenharmony_ci    0xBB,       /* dest |= ~src;        DSno,   GXorInverted,   0xD */
4462306a36Sopenharmony_ci    0x77,       /* dest = ~src|~dest;   DSan,   GXnand,         0xE */
4562306a36Sopenharmony_ci    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci/* same ROP but with Pattern as Source */
4862306a36Sopenharmony_cistatic const u8 sisPatALUConv[] =
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci    0x00,       /* dest = 0;            0,      GXclear,        0 */
5162306a36Sopenharmony_ci    0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
5262306a36Sopenharmony_ci    0x50,       /* dest = src & ~dest;  PDna,   GXandReverse,   0x2 */
5362306a36Sopenharmony_ci    0xF0,       /* dest = src;          P,      GXcopy,         0x3 */
5462306a36Sopenharmony_ci    0x0A,       /* dest &= ~src;        DPna,   GXandInverted,  0x4 */
5562306a36Sopenharmony_ci    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
5662306a36Sopenharmony_ci    0x5A,       /* dest = ^src;         DPx,    GXxor,          0x6 */
5762306a36Sopenharmony_ci    0xFA,       /* dest |= src;         DPo,    GXor,           0x7 */
5862306a36Sopenharmony_ci    0x05,       /* dest = ~src & ~dest; DPon,   GXnor,          0x8 */
5962306a36Sopenharmony_ci    0xA5,       /* dest ^= ~src ;       DPxn,   GXequiv,        0x9 */
6062306a36Sopenharmony_ci    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
6162306a36Sopenharmony_ci    0xF5,       /* dest = src|~dest ;   PDno,   GXorReverse,    0xB */
6262306a36Sopenharmony_ci    0x0F,       /* dest = ~src;         Pn,     GXcopyInverted, 0xC */
6362306a36Sopenharmony_ci    0xAF,       /* dest |= ~src;        DPno,   GXorInverted,   0xD */
6462306a36Sopenharmony_ci    0x5F,       /* dest = ~src|~dest;   DPan,   GXnand,         0xE */
6562306a36Sopenharmony_ci    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic const int myrops[] = {
6962306a36Sopenharmony_ci   	3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* 300 series ----------------------------------------------------- */
7362306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
7462306a36Sopenharmony_cistatic void
7562306a36Sopenharmony_ciSiS300Sync(struct sis_video_info *ivideo)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	SiS300Idle
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void
8162306a36Sopenharmony_ciSiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir,
8262306a36Sopenharmony_ci                                 int rop, int trans_color)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	SiS300SetupDSTColorDepth(ivideo->DstColor);
8562306a36Sopenharmony_ci	SiS300SetupSRCPitch(ivideo->video_linelength)
8662306a36Sopenharmony_ci	SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if(trans_color != -1) {
8962306a36Sopenharmony_ci		SiS300SetupROP(0x0A)
9062306a36Sopenharmony_ci		SiS300SetupSRCTrans(trans_color)
9162306a36Sopenharmony_ci		SiS300SetupCMDFlag(TRANSPARENT_BITBLT)
9262306a36Sopenharmony_ci	} else {
9362306a36Sopenharmony_ci	        SiS300SetupROP(sisALUConv[rop])
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci	if(xdir > 0) {
9662306a36Sopenharmony_ci		SiS300SetupCMDFlag(X_INC)
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci	if(ydir > 0) {
9962306a36Sopenharmony_ci		SiS300SetupCMDFlag(Y_INC)
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic void
10462306a36Sopenharmony_ciSiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x,
10562306a36Sopenharmony_ci				   int src_y, int dst_x, int dst_y, int width, int height)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	u32 srcbase = 0, dstbase = 0;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if(src_y >= 2048) {
11062306a36Sopenharmony_ci		srcbase = ivideo->video_linelength * src_y;
11162306a36Sopenharmony_ci		src_y = 0;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	if(dst_y >= 2048) {
11462306a36Sopenharmony_ci		dstbase = ivideo->video_linelength * dst_y;
11562306a36Sopenharmony_ci		dst_y = 0;
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	SiS300SetupSRCBase(srcbase);
11962306a36Sopenharmony_ci	SiS300SetupDSTBase(dstbase);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if(!(ivideo->CommandReg & X_INC))  {
12262306a36Sopenharmony_ci		src_x += width-1;
12362306a36Sopenharmony_ci		dst_x += width-1;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci	if(!(ivideo->CommandReg & Y_INC))  {
12662306a36Sopenharmony_ci		src_y += height-1;
12762306a36Sopenharmony_ci		dst_y += height-1;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci	SiS300SetupRect(width, height)
13062306a36Sopenharmony_ci	SiS300SetupSRCXY(src_x, src_y)
13162306a36Sopenharmony_ci	SiS300SetupDSTXY(dst_x, dst_y)
13262306a36Sopenharmony_ci	SiS300DoCMD
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void
13662306a36Sopenharmony_ciSiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	SiS300SetupPATFG(color)
13962306a36Sopenharmony_ci	SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
14062306a36Sopenharmony_ci	SiS300SetupDSTColorDepth(ivideo->DstColor);
14162306a36Sopenharmony_ci	SiS300SetupROP(sisPatALUConv[rop])
14262306a36Sopenharmony_ci	SiS300SetupCMDFlag(PATFG)
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic void
14662306a36Sopenharmony_ciSiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	u32 dstbase = 0;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if(y >= 2048) {
15162306a36Sopenharmony_ci		dstbase = ivideo->video_linelength * y;
15262306a36Sopenharmony_ci		y = 0;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci	SiS300SetupDSTBase(dstbase)
15562306a36Sopenharmony_ci	SiS300SetupDSTXY(x,y)
15662306a36Sopenharmony_ci	SiS300SetupRect(w,h)
15762306a36Sopenharmony_ci	SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT)
15862306a36Sopenharmony_ci	SiS300DoCMD
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci#endif
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/* 315/330/340 series ---------------------------------------------- */
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
16562306a36Sopenharmony_cistatic void
16662306a36Sopenharmony_ciSiS310Sync(struct sis_video_info *ivideo)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	SiS310Idle
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void
17262306a36Sopenharmony_ciSiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	SiS310SetupDSTColorDepth(ivideo->DstColor);
17562306a36Sopenharmony_ci	SiS310SetupSRCPitch(ivideo->video_linelength)
17662306a36Sopenharmony_ci	SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff)
17762306a36Sopenharmony_ci	if(trans_color != -1) {
17862306a36Sopenharmony_ci		SiS310SetupROP(0x0A)
17962306a36Sopenharmony_ci		SiS310SetupSRCTrans(trans_color)
18062306a36Sopenharmony_ci		SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
18162306a36Sopenharmony_ci	} else {
18262306a36Sopenharmony_ci	        SiS310SetupROP(sisALUConv[rop])
18362306a36Sopenharmony_ci		/* Set command - not needed, both 0 */
18462306a36Sopenharmony_ci		/* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci	SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth)
18762306a36Sopenharmony_ci	/* The chip is smart enough to know the direction */
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic void
19162306a36Sopenharmony_ciSiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y,
19262306a36Sopenharmony_ci			 int dst_x, int dst_y, int width, int height)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	u32 srcbase = 0, dstbase = 0;
19562306a36Sopenharmony_ci	int mymin = min(src_y, dst_y);
19662306a36Sopenharmony_ci	int mymax = max(src_y, dst_y);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* Although the chip knows the direction to use
19962306a36Sopenharmony_ci	 * if the source and destination areas overlap,
20062306a36Sopenharmony_ci	 * that logic fails if we fiddle with the bitmap
20162306a36Sopenharmony_ci	 * addresses. Therefore, we check if the source
20262306a36Sopenharmony_ci	 * and destination blitting areas overlap and
20362306a36Sopenharmony_ci	 * adapt the bitmap addresses synchronously
20462306a36Sopenharmony_ci	 * if the coordinates exceed the valid range.
20562306a36Sopenharmony_ci	 * The areas do not overlap, we do our
20662306a36Sopenharmony_ci	 * normal check.
20762306a36Sopenharmony_ci	 */
20862306a36Sopenharmony_ci	if((mymax - mymin) < height) {
20962306a36Sopenharmony_ci		if((src_y >= 2048) || (dst_y >= 2048)) {
21062306a36Sopenharmony_ci			srcbase = ivideo->video_linelength * mymin;
21162306a36Sopenharmony_ci			dstbase = ivideo->video_linelength * mymin;
21262306a36Sopenharmony_ci			src_y -= mymin;
21362306a36Sopenharmony_ci			dst_y -= mymin;
21462306a36Sopenharmony_ci		}
21562306a36Sopenharmony_ci	} else {
21662306a36Sopenharmony_ci		if(src_y >= 2048) {
21762306a36Sopenharmony_ci			srcbase = ivideo->video_linelength * src_y;
21862306a36Sopenharmony_ci			src_y = 0;
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci		if(dst_y >= 2048) {
22162306a36Sopenharmony_ci			dstbase = ivideo->video_linelength * dst_y;
22262306a36Sopenharmony_ci			dst_y = 0;
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	srcbase += ivideo->video_offset;
22762306a36Sopenharmony_ci	dstbase += ivideo->video_offset;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	SiS310SetupSRCBase(srcbase);
23062306a36Sopenharmony_ci	SiS310SetupDSTBase(dstbase);
23162306a36Sopenharmony_ci	SiS310SetupRect(width, height)
23262306a36Sopenharmony_ci	SiS310SetupSRCXY(src_x, src_y)
23362306a36Sopenharmony_ci	SiS310SetupDSTXY(dst_x, dst_y)
23462306a36Sopenharmony_ci	SiS310DoCMD
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic void
23862306a36Sopenharmony_ciSiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	SiS310SetupPATFG(color)
24162306a36Sopenharmony_ci	SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff)
24262306a36Sopenharmony_ci	SiS310SetupDSTColorDepth(ivideo->DstColor);
24362306a36Sopenharmony_ci	SiS310SetupROP(sisPatALUConv[rop])
24462306a36Sopenharmony_ci	SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth)
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic void
24862306a36Sopenharmony_ciSiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	u32 dstbase = 0;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if(y >= 2048) {
25362306a36Sopenharmony_ci		dstbase = ivideo->video_linelength * y;
25462306a36Sopenharmony_ci		y = 0;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci	dstbase += ivideo->video_offset;
25762306a36Sopenharmony_ci	SiS310SetupDSTBase(dstbase)
25862306a36Sopenharmony_ci	SiS310SetupDSTXY(x,y)
25962306a36Sopenharmony_ci	SiS310SetupRect(w,h)
26062306a36Sopenharmony_ci	SiS310SetupCMDFlag(BITBLT)
26162306a36Sopenharmony_ci	SiS310DoCMD
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci#endif
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci/* --------------------------------------------------------------------- */
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/* The exported routines */
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ciint sisfb_initaccel(struct sis_video_info *ivideo)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci#ifdef SISFB_USE_SPINLOCKS
27262306a36Sopenharmony_ci	spin_lock_init(&ivideo->lockaccel);
27362306a36Sopenharmony_ci#endif
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_civoid sisfb_syncaccel(struct sis_video_info *ivideo)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
28062306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
28162306a36Sopenharmony_ci		SiS300Sync(ivideo);
28262306a36Sopenharmony_ci#endif
28362306a36Sopenharmony_ci	} else {
28462306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
28562306a36Sopenharmony_ci		SiS310Sync(ivideo);
28662306a36Sopenharmony_ci#endif
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ciint fbcon_sis_sync(struct fb_info *info)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
29362306a36Sopenharmony_ci	CRITFLAGS
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if((!ivideo->accel) || (!ivideo->engineok))
29662306a36Sopenharmony_ci		return 0;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	CRITBEGIN
29962306a36Sopenharmony_ci	sisfb_syncaccel(ivideo);
30062306a36Sopenharmony_ci	CRITEND
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	return 0;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_civoid fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
30862306a36Sopenharmony_ci	u32 col = 0;
30962306a36Sopenharmony_ci	u32 vxres = info->var.xres_virtual;
31062306a36Sopenharmony_ci	u32 vyres = info->var.yres_virtual;
31162306a36Sopenharmony_ci	int width, height;
31262306a36Sopenharmony_ci	CRITFLAGS
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if(info->state != FBINFO_STATE_RUNNING)
31562306a36Sopenharmony_ci		return;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if((!ivideo->accel) || (!ivideo->engineok)) {
31862306a36Sopenharmony_ci		cfb_fillrect(info, rect);
31962306a36Sopenharmony_ci		return;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres)
32362306a36Sopenharmony_ci		return;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* Clipping */
32662306a36Sopenharmony_ci	width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width;
32762306a36Sopenharmony_ci	height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	switch(info->var.bits_per_pixel) {
33062306a36Sopenharmony_ci	case 8:  col = rect->color;
33162306a36Sopenharmony_ci		 break;
33262306a36Sopenharmony_ci	case 16:
33362306a36Sopenharmony_ci	case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
33462306a36Sopenharmony_ci		 break;
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
33862306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
33962306a36Sopenharmony_ci		CRITBEGIN
34062306a36Sopenharmony_ci		SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]);
34162306a36Sopenharmony_ci		SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
34262306a36Sopenharmony_ci		CRITEND
34362306a36Sopenharmony_ci#endif
34462306a36Sopenharmony_ci	} else {
34562306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
34662306a36Sopenharmony_ci		CRITBEGIN
34762306a36Sopenharmony_ci		SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]);
34862306a36Sopenharmony_ci		SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
34962306a36Sopenharmony_ci		CRITEND
35062306a36Sopenharmony_ci#endif
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	sisfb_syncaccel(ivideo);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_civoid fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
35962306a36Sopenharmony_ci	u32 vxres = info->var.xres_virtual;
36062306a36Sopenharmony_ci	u32 vyres = info->var.yres_virtual;
36162306a36Sopenharmony_ci	int width = area->width;
36262306a36Sopenharmony_ci	int height = area->height;
36362306a36Sopenharmony_ci	CRITFLAGS
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if(info->state != FBINFO_STATE_RUNNING)
36662306a36Sopenharmony_ci		return;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if((!ivideo->accel) || (!ivideo->engineok)) {
36962306a36Sopenharmony_ci		cfb_copyarea(info, area);
37062306a36Sopenharmony_ci		return;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if(!width || !height ||
37462306a36Sopenharmony_ci	   area->sx >= vxres || area->sy >= vyres ||
37562306a36Sopenharmony_ci	   area->dx >= vxres || area->dy >= vyres)
37662306a36Sopenharmony_ci		return;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* Clipping */
37962306a36Sopenharmony_ci	if((area->sx + width) > vxres) width = vxres - area->sx;
38062306a36Sopenharmony_ci	if((area->dx + width) > vxres) width = vxres - area->dx;
38162306a36Sopenharmony_ci	if((area->sy + height) > vyres) height = vyres - area->sy;
38262306a36Sopenharmony_ci	if((area->dy + height) > vyres) height = vyres - area->dy;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if(ivideo->sisvga_engine == SIS_300_VGA) {
38562306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_300
38662306a36Sopenharmony_ci		int xdir, ydir;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		if(area->sx < area->dx) xdir = 0;
38962306a36Sopenharmony_ci		else                    xdir = 1;
39062306a36Sopenharmony_ci		if(area->sy < area->dy) ydir = 0;
39162306a36Sopenharmony_ci		else                    ydir = 1;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		CRITBEGIN
39462306a36Sopenharmony_ci		SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1);
39562306a36Sopenharmony_ci		SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy,
39662306a36Sopenharmony_ci					area->dx, area->dy, width, height);
39762306a36Sopenharmony_ci		CRITEND
39862306a36Sopenharmony_ci#endif
39962306a36Sopenharmony_ci	} else {
40062306a36Sopenharmony_ci#ifdef CONFIG_FB_SIS_315
40162306a36Sopenharmony_ci		CRITBEGIN
40262306a36Sopenharmony_ci		SiS310SetupForScreenToScreenCopy(ivideo, 3, -1);
40362306a36Sopenharmony_ci		SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy,
40462306a36Sopenharmony_ci					area->dx, area->dy, width, height);
40562306a36Sopenharmony_ci		CRITEND
40662306a36Sopenharmony_ci#endif
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	sisfb_syncaccel(ivideo);
41062306a36Sopenharmony_ci}
411