linux/drivers/video/fbdev/sis/sis_accel.c
<<
>>
Prefs
   1/*
   2 * SiS 300/540/630[S]/730[S],
   3 * SiS 315[E|PRO]/550/[M]650/651/[M]661[F|M]X/740/[M]741[GX]/330/[M]760[GX],
   4 * XGI V3XT/V5/V8, Z7
   5 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
   6 *
   7 * 2D acceleration part
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the named License,
  12 * or any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  22 *
  23 * Based on the XFree86/X.org driver which is
  24 *     Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
  25 *
  26 * Author: Thomas Winischhofer <thomas@winischhofer.net>
  27 *                      (see http://www.winischhofer.net/
  28 *                      for more information and updates)
  29 */
  30
  31#include <linux/module.h>
  32#include <linux/kernel.h>
  33#include <linux/fb.h>
  34#include <linux/ioport.h>
  35#include <linux/types.h>
  36#include <asm/io.h>
  37
  38#include "sis.h"
  39#include "sis_accel.h"
  40
  41static const u8 sisALUConv[] =
  42{
  43    0x00,       /* dest = 0;            0,      GXclear,        0 */
  44    0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
  45    0x44,       /* dest = src & ~dest;  SDna,   GXandReverse,   0x2 */
  46    0xCC,       /* dest = src;          S,      GXcopy,         0x3 */
  47    0x22,       /* dest &= ~src;        DSna,   GXandInverted,  0x4 */
  48    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
  49    0x66,       /* dest = ^src;         DSx,    GXxor,          0x6 */
  50    0xEE,       /* dest |= src;         DSo,    GXor,           0x7 */
  51    0x11,       /* dest = ~src & ~dest; DSon,   GXnor,          0x8 */
  52    0x99,       /* dest ^= ~src ;       DSxn,   GXequiv,        0x9 */
  53    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
  54    0xDD,       /* dest = src|~dest ;   SDno,   GXorReverse,    0xB */
  55    0x33,       /* dest = ~src;         Sn,     GXcopyInverted, 0xC */
  56    0xBB,       /* dest |= ~src;        DSno,   GXorInverted,   0xD */
  57    0x77,       /* dest = ~src|~dest;   DSan,   GXnand,         0xE */
  58    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
  59};
  60/* same ROP but with Pattern as Source */
  61static const u8 sisPatALUConv[] =
  62{
  63    0x00,       /* dest = 0;            0,      GXclear,        0 */
  64    0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
  65    0x50,       /* dest = src & ~dest;  PDna,   GXandReverse,   0x2 */
  66    0xF0,       /* dest = src;          P,      GXcopy,         0x3 */
  67    0x0A,       /* dest &= ~src;        DPna,   GXandInverted,  0x4 */
  68    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
  69    0x5A,       /* dest = ^src;         DPx,    GXxor,          0x6 */
  70    0xFA,       /* dest |= src;         DPo,    GXor,           0x7 */
  71    0x05,       /* dest = ~src & ~dest; DPon,   GXnor,          0x8 */
  72    0xA5,       /* dest ^= ~src ;       DPxn,   GXequiv,        0x9 */
  73    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
  74    0xF5,       /* dest = src|~dest ;   PDno,   GXorReverse,    0xB */
  75    0x0F,       /* dest = ~src;         Pn,     GXcopyInverted, 0xC */
  76    0xAF,       /* dest |= ~src;        DPno,   GXorInverted,   0xD */
  77    0x5F,       /* dest = ~src|~dest;   DPan,   GXnand,         0xE */
  78    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
  79};
  80
  81static const int myrops[] = {
  82        3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
  83};
  84
  85/* 300 series ----------------------------------------------------- */
  86#ifdef CONFIG_FB_SIS_300
  87static void
  88SiS300Sync(struct sis_video_info *ivideo)
  89{
  90        SiS300Idle
  91}
  92
  93static void
  94SiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir,
  95                                 int rop, int trans_color)
  96{
  97        SiS300SetupDSTColorDepth(ivideo->DstColor);
  98        SiS300SetupSRCPitch(ivideo->video_linelength)
  99        SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
 100
 101        if(trans_color != -1) {
 102                SiS300SetupROP(0x0A)
 103                SiS300SetupSRCTrans(trans_color)
 104                SiS300SetupCMDFlag(TRANSPARENT_BITBLT)
 105        } else {
 106                SiS300SetupROP(sisALUConv[rop])
 107        }
 108        if(xdir > 0) {
 109                SiS300SetupCMDFlag(X_INC)
 110        }
 111        if(ydir > 0) {
 112                SiS300SetupCMDFlag(Y_INC)
 113        }
 114}
 115
 116static void
 117SiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x,
 118                                   int src_y, int dst_x, int dst_y, int width, int height)
 119{
 120        u32 srcbase = 0, dstbase = 0;
 121
 122        if(src_y >= 2048) {
 123                srcbase = ivideo->video_linelength * src_y;
 124                src_y = 0;
 125        }
 126        if(dst_y >= 2048) {
 127                dstbase = ivideo->video_linelength * dst_y;
 128                dst_y = 0;
 129        }
 130
 131        SiS300SetupSRCBase(srcbase);
 132        SiS300SetupDSTBase(dstbase);
 133
 134        if(!(ivideo->CommandReg & X_INC))  {
 135                src_x += width-1;
 136                dst_x += width-1;
 137        }
 138        if(!(ivideo->CommandReg & Y_INC))  {
 139                src_y += height-1;
 140                dst_y += height-1;
 141        }
 142        SiS300SetupRect(width, height)
 143        SiS300SetupSRCXY(src_x, src_y)
 144        SiS300SetupDSTXY(dst_x, dst_y)
 145        SiS300DoCMD
 146}
 147
 148static void
 149SiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
 150{
 151        SiS300SetupPATFG(color)
 152        SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
 153        SiS300SetupDSTColorDepth(ivideo->DstColor);
 154        SiS300SetupROP(sisPatALUConv[rop])
 155        SiS300SetupCMDFlag(PATFG)
 156}
 157
 158static void
 159SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
 160{
 161        u32 dstbase = 0;
 162
 163        if(y >= 2048) {
 164                dstbase = ivideo->video_linelength * y;
 165                y = 0;
 166        }
 167        SiS300SetupDSTBase(dstbase)
 168        SiS300SetupDSTXY(x,y)
 169        SiS300SetupRect(w,h)
 170        SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT)
 171        SiS300DoCMD
 172}
 173#endif
 174
 175/* 315/330/340 series ---------------------------------------------- */
 176
 177#ifdef CONFIG_FB_SIS_315
 178static void
 179SiS310Sync(struct sis_video_info *ivideo)
 180{
 181        SiS310Idle
 182}
 183
 184static void
 185SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color)
 186{
 187        SiS310SetupDSTColorDepth(ivideo->DstColor);
 188        SiS310SetupSRCPitch(ivideo->video_linelength)
 189        SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff)
 190        if(trans_color != -1) {
 191                SiS310SetupROP(0x0A)
 192                SiS310SetupSRCTrans(trans_color)
 193                SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
 194        } else {
 195                SiS310SetupROP(sisALUConv[rop])
 196                /* Set command - not needed, both 0 */
 197                /* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
 198        }
 199        SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth)
 200        /* The chip is smart enough to know the direction */
 201}
 202
 203static void
 204SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y,
 205                         int dst_x, int dst_y, int width, int height)
 206{
 207        u32 srcbase = 0, dstbase = 0;
 208        int mymin = min(src_y, dst_y);
 209        int mymax = max(src_y, dst_y);
 210
 211        /* Although the chip knows the direction to use
 212         * if the source and destination areas overlap,
 213         * that logic fails if we fiddle with the bitmap
 214         * addresses. Therefore, we check if the source
 215         * and destination blitting areas overlap and
 216         * adapt the bitmap addresses synchronously
 217         * if the coordinates exceed the valid range.
 218         * The the areas do not overlap, we do our
 219         * normal check.
 220         */
 221        if((mymax - mymin) < height) {
 222                if((src_y >= 2048) || (dst_y >= 2048)) {
 223                        srcbase = ivideo->video_linelength * mymin;
 224                        dstbase = ivideo->video_linelength * mymin;
 225                        src_y -= mymin;
 226                        dst_y -= mymin;
 227                }
 228        } else {
 229                if(src_y >= 2048) {
 230                        srcbase = ivideo->video_linelength * src_y;
 231                        src_y = 0;
 232                }
 233                if(dst_y >= 2048) {
 234                        dstbase = ivideo->video_linelength * dst_y;
 235                        dst_y = 0;
 236                }
 237        }
 238
 239        srcbase += ivideo->video_offset;
 240        dstbase += ivideo->video_offset;
 241
 242        SiS310SetupSRCBase(srcbase);
 243        SiS310SetupDSTBase(dstbase);
 244        SiS310SetupRect(width, height)
 245        SiS310SetupSRCXY(src_x, src_y)
 246        SiS310SetupDSTXY(dst_x, dst_y)
 247        SiS310DoCMD
 248}
 249
 250static void
 251SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
 252{
 253        SiS310SetupPATFG(color)
 254        SiS310SetupDSTRect(ivideo->video_linelength, 0x0fff)
 255        SiS310SetupDSTColorDepth(ivideo->DstColor);
 256        SiS310SetupROP(sisPatALUConv[rop])
 257        SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth)
 258}
 259
 260static void
 261SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
 262{
 263        u32 dstbase = 0;
 264
 265        if(y >= 2048) {
 266                dstbase = ivideo->video_linelength * y;
 267                y = 0;
 268        }
 269        dstbase += ivideo->video_offset;
 270        SiS310SetupDSTBase(dstbase)
 271        SiS310SetupDSTXY(x,y)
 272        SiS310SetupRect(w,h)
 273        SiS310SetupCMDFlag(BITBLT)
 274        SiS310DoCMD
 275}
 276#endif
 277
 278/* --------------------------------------------------------------------- */
 279
 280/* The exported routines */
 281
 282int sisfb_initaccel(struct sis_video_info *ivideo)
 283{
 284#ifdef SISFB_USE_SPINLOCKS
 285        spin_lock_init(&ivideo->lockaccel);
 286#endif
 287        return 0;
 288}
 289
 290void sisfb_syncaccel(struct sis_video_info *ivideo)
 291{
 292        if(ivideo->sisvga_engine == SIS_300_VGA) {
 293#ifdef CONFIG_FB_SIS_300
 294                SiS300Sync(ivideo);
 295#endif
 296        } else {
 297#ifdef CONFIG_FB_SIS_315
 298                SiS310Sync(ivideo);
 299#endif
 300        }
 301}
 302
 303int fbcon_sis_sync(struct fb_info *info)
 304{
 305        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 306        CRITFLAGS
 307
 308        if((!ivideo->accel) || (!ivideo->engineok))
 309                return 0;
 310
 311        CRITBEGIN
 312        sisfb_syncaccel(ivideo);
 313        CRITEND
 314
 315        return 0;
 316}
 317
 318void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 319{
 320        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 321        u32 col = 0;
 322        u32 vxres = info->var.xres_virtual;
 323        u32 vyres = info->var.yres_virtual;
 324        int width, height;
 325        CRITFLAGS
 326
 327        if(info->state != FBINFO_STATE_RUNNING)
 328                return;
 329
 330        if((!ivideo->accel) || (!ivideo->engineok)) {
 331                cfb_fillrect(info, rect);
 332                return;
 333        }
 334
 335        if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres)
 336                return;
 337
 338        /* Clipping */
 339        width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width;
 340        height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height;
 341
 342        switch(info->var.bits_per_pixel) {
 343        case 8:  col = rect->color;
 344                 break;
 345        case 16:
 346        case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
 347                 break;
 348        }
 349
 350        if(ivideo->sisvga_engine == SIS_300_VGA) {
 351#ifdef CONFIG_FB_SIS_300
 352                CRITBEGIN
 353                SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]);
 354                SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
 355                CRITEND
 356#endif
 357        } else {
 358#ifdef CONFIG_FB_SIS_315
 359                CRITBEGIN
 360                SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]);
 361                SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
 362                CRITEND
 363#endif
 364        }
 365
 366        sisfb_syncaccel(ivideo);
 367}
 368
 369void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 370{
 371        struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 372        u32 vxres = info->var.xres_virtual;
 373        u32 vyres = info->var.yres_virtual;
 374        int width = area->width;
 375        int height = area->height;
 376        CRITFLAGS
 377
 378        if(info->state != FBINFO_STATE_RUNNING)
 379                return;
 380
 381        if((!ivideo->accel) || (!ivideo->engineok)) {
 382                cfb_copyarea(info, area);
 383                return;
 384        }
 385
 386        if(!width || !height ||
 387           area->sx >= vxres || area->sy >= vyres ||
 388           area->dx >= vxres || area->dy >= vyres)
 389                return;
 390
 391        /* Clipping */
 392        if((area->sx + width) > vxres) width = vxres - area->sx;
 393        if((area->dx + width) > vxres) width = vxres - area->dx;
 394        if((area->sy + height) > vyres) height = vyres - area->sy;
 395        if((area->dy + height) > vyres) height = vyres - area->dy;
 396
 397        if(ivideo->sisvga_engine == SIS_300_VGA) {
 398#ifdef CONFIG_FB_SIS_300
 399                int xdir, ydir;
 400
 401                if(area->sx < area->dx) xdir = 0;
 402                else                    xdir = 1;
 403                if(area->sy < area->dy) ydir = 0;
 404                else                    ydir = 1;
 405
 406                CRITBEGIN
 407                SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1);
 408                SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy,
 409                                        area->dx, area->dy, width, height);
 410                CRITEND
 411#endif
 412        } else {
 413#ifdef CONFIG_FB_SIS_315
 414                CRITBEGIN
 415                SiS310SetupForScreenToScreenCopy(ivideo, 3, -1);
 416                SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy,
 417                                        area->dx, area->dy, width, height);
 418                CRITEND
 419#endif
 420        }
 421
 422        sisfb_syncaccel(ivideo);
 423}
 424