linux/drivers/video/matrox/matroxfb_accel.c
<<
>>
Prefs
   1/*
   2 *
   3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
   4 *
   5 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
   6 *
   7 * Version: 1.65 2002/08/14
   8 *
   9 * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  10 *
  11 * Contributors: "menion?" <menion@mindless.com>
  12 *                     Betatesting, fixes, ideas
  13 *
  14 *               "Kurt Garloff" <garloff@suse.de>
  15 *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
  16 *
  17 *               "Tom Rini" <trini@kernel.crashing.org>
  18 *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
  19 *
  20 *               "Bibek Sahu" <scorpio@dodds.net>
  21 *                     Access device through readb|w|l and write b|w|l
  22 *                     Extensive debugging stuff
  23 *
  24 *               "Daniel Haun" <haund@usa.net>
  25 *                     Testing, hardware cursor fixes
  26 *
  27 *               "Scott Wood" <sawst46+@pitt.edu>
  28 *                     Fixes
  29 *
  30 *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
  31 *                     Betatesting
  32 *
  33 *               "Kelly French" <targon@hazmat.com>
  34 *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
  35 *                     Betatesting, bug reporting
  36 *
  37 *               "Pablo Bianucci" <pbian@pccp.com.ar>
  38 *                     Fixes, ideas, betatesting
  39 *
  40 *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
  41 *                     Fixes, enhandcements, ideas, betatesting
  42 *
  43 *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
  44 *                     PPC betatesting, PPC support, backward compatibility
  45 *
  46 *               "Paul Womar" <Paul@pwomar.demon.co.uk>
  47 *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
  48 *                     PPC betatesting
  49 *
  50 *               "Thomas Pornin" <pornin@bolet.ens.fr>
  51 *                     Alpha betatesting
  52 *
  53 *               "Pieter van Leuven" <pvl@iae.nl>
  54 *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
  55 *                     G100 testing
  56 *
  57 *               "H. Peter Arvin" <hpa@transmeta.com>
  58 *                     Ideas
  59 *
  60 *               "Cort Dougan" <cort@cs.nmt.edu>
  61 *                     CHRP fixes and PReP cleanup
  62 *
  63 *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
  64 *                     G400 support
  65 *
  66 * (following author is not in any relation with this code, but his code
  67 *  is included in this driver)
  68 *
  69 * Based on framebuffer driver for VBE 2.0 compliant graphic boards
  70 *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  71 *
  72 * (following author is not in any relation with this code, but his ideas
  73 *  were used when writing this driver)
  74 *
  75 *               FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  76 *
  77 */
  78
  79#include "matroxfb_accel.h"
  80#include "matroxfb_DAC1064.h"
  81#include "matroxfb_Ti3026.h"
  82#include "matroxfb_misc.h"
  83
  84#define curr_ydstorg(x) ((x)->curr.ydstorg.pixels)
  85
  86#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
  87
  88static inline void matrox_cfb4_pal(u_int32_t* pal) {
  89        unsigned int i;
  90        
  91        for (i = 0; i < 16; i++) {
  92                pal[i] = i * 0x11111111U;
  93        }
  94}
  95
  96static inline void matrox_cfb8_pal(u_int32_t* pal) {
  97        unsigned int i;
  98        
  99        for (i = 0; i < 16; i++) {
 100                pal[i] = i * 0x01010101U;
 101        }
 102}
 103
 104static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area);
 105static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
 106static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image);
 107static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
 108static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area);
 109
 110void matrox_cfbX_init(struct matrox_fb_info *minfo)
 111{
 112        u_int32_t maccess;
 113        u_int32_t mpitch;
 114        u_int32_t mopmode;
 115        int accel;
 116
 117        DBG(__func__)
 118
 119        mpitch = minfo->fbcon.var.xres_virtual;
 120
 121        minfo->fbops.fb_copyarea = cfb_copyarea;
 122        minfo->fbops.fb_fillrect = cfb_fillrect;
 123        minfo->fbops.fb_imageblit = cfb_imageblit;
 124        minfo->fbops.fb_cursor = NULL;
 125
 126        accel = (minfo->fbcon.var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT;
 127
 128        switch (minfo->fbcon.var.bits_per_pixel) {
 129                case 4:         maccess = 0x00000000;   /* accelerate as 8bpp video */
 130                                mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
 131                                mopmode = M_OPMODE_4BPP;
 132                                matrox_cfb4_pal(minfo->cmap);
 133                                if (accel && !(mpitch & 1)) {
 134                                        minfo->fbops.fb_copyarea = matroxfb_cfb4_copyarea;
 135                                        minfo->fbops.fb_fillrect = matroxfb_cfb4_fillrect;
 136                                }
 137                                break;
 138                case 8:         maccess = 0x00000000;
 139                                mopmode = M_OPMODE_8BPP;
 140                                matrox_cfb8_pal(minfo->cmap);
 141                                if (accel) {
 142                                        minfo->fbops.fb_copyarea = matroxfb_copyarea;
 143                                        minfo->fbops.fb_fillrect = matroxfb_fillrect;
 144                                        minfo->fbops.fb_imageblit = matroxfb_imageblit;
 145                                }
 146                                break;
 147                case 16:        if (minfo->fbcon.var.green.length == 5)
 148                                        maccess = 0xC0000001;
 149                                else
 150                                        maccess = 0x40000001;
 151                                mopmode = M_OPMODE_16BPP;
 152                                if (accel) {
 153                                        minfo->fbops.fb_copyarea = matroxfb_copyarea;
 154                                        minfo->fbops.fb_fillrect = matroxfb_fillrect;
 155                                        minfo->fbops.fb_imageblit = matroxfb_imageblit;
 156                                }
 157                                break;
 158                case 24:        maccess = 0x00000003;
 159                                mopmode = M_OPMODE_24BPP;
 160                                if (accel) {
 161                                        minfo->fbops.fb_copyarea = matroxfb_copyarea;
 162                                        minfo->fbops.fb_fillrect = matroxfb_fillrect;
 163                                        minfo->fbops.fb_imageblit = matroxfb_imageblit;
 164                                }
 165                                break;
 166                case 32:        maccess = 0x00000002;
 167                                mopmode = M_OPMODE_32BPP;
 168                                if (accel) {
 169                                        minfo->fbops.fb_copyarea = matroxfb_copyarea;
 170                                        minfo->fbops.fb_fillrect = matroxfb_fillrect;
 171                                        minfo->fbops.fb_imageblit = matroxfb_imageblit;
 172                                }
 173                                break;
 174                default:        maccess = 0x00000000;
 175                                mopmode = 0x00000000;
 176                                break;  /* turn off acceleration!!! */
 177        }
 178        mga_fifo(8);
 179        mga_outl(M_PITCH, mpitch);
 180        mga_outl(M_YDSTORG, curr_ydstorg(minfo));
 181        if (minfo->capable.plnwt)
 182                mga_outl(M_PLNWT, -1);
 183        if (minfo->capable.srcorg) {
 184                mga_outl(M_SRCORG, 0);
 185                mga_outl(M_DSTORG, 0);
 186        }
 187        mga_outl(M_OPMODE, mopmode);
 188        mga_outl(M_CXBNDRY, 0xFFFF0000);
 189        mga_outl(M_YTOP, 0);
 190        mga_outl(M_YBOT, 0x01FFFFFF);
 191        mga_outl(M_MACCESS, maccess);
 192        minfo->accel.m_dwg_rect = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
 193        if (isMilleniumII(minfo)) minfo->accel.m_dwg_rect |= M_DWG_TRANSC;
 194        minfo->accel.m_opmode = mopmode;
 195}
 196
 197EXPORT_SYMBOL(matrox_cfbX_init);
 198
 199static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
 200                               int sx, int dy, int dx, int height, int width)
 201{
 202        int start, end;
 203        CRITFLAGS
 204
 205        DBG(__func__)
 206
 207        CRITBEGIN
 208
 209        if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
 210                mga_fifo(2);
 211                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
 212                         M_DWG_BFCOL | M_DWG_REPLACE);
 213                mga_outl(M_AR5, vxres);
 214                width--;
 215                start = sy*vxres+sx+curr_ydstorg(minfo);
 216                end = start+width;
 217        } else {
 218                mga_fifo(3);
 219                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
 220                mga_outl(M_SGN, 5);
 221                mga_outl(M_AR5, -vxres);
 222                width--;
 223                end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
 224                start = end+width;
 225                dy += height-1;
 226        }
 227        mga_fifo(4);
 228        mga_outl(M_AR0, end);
 229        mga_outl(M_AR3, start);
 230        mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
 231        mga_ydstlen(dy, height);
 232        WaitTillIdle();
 233
 234        CRITEND
 235}
 236
 237static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres,
 238                                   int sy, int sx, int dy, int dx, int height,
 239                                   int width)
 240{
 241        int start, end;
 242        CRITFLAGS
 243
 244        DBG(__func__)
 245
 246        CRITBEGIN
 247
 248        if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
 249                mga_fifo(2);
 250                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
 251                        M_DWG_BFCOL | M_DWG_REPLACE);
 252                mga_outl(M_AR5, vxres);
 253                width--;
 254                start = sy*vxres+sx+curr_ydstorg(minfo);
 255                end = start+width;
 256        } else {
 257                mga_fifo(3);
 258                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
 259                mga_outl(M_SGN, 5);
 260                mga_outl(M_AR5, -vxres);
 261                width--;
 262                end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
 263                start = end+width;
 264                dy += height-1;
 265        }
 266        mga_fifo(5);
 267        mga_outl(M_AR0, end);
 268        mga_outl(M_AR3, start);
 269        mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
 270        mga_outl(M_YDST, dy*vxres >> 5);
 271        mga_outl(M_LEN | M_EXEC, height);
 272        WaitTillIdle();
 273
 274        CRITEND
 275}
 276
 277static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
 278        struct matrox_fb_info *minfo = info2minfo(info);
 279
 280        if ((area->sx | area->dx | area->width) & 1)
 281                cfb_copyarea(info, area);
 282        else
 283                matrox_accel_bmove_lin(minfo, minfo->fbcon.var.xres_virtual >> 1, area->sy, area->sx >> 1, area->dy, area->dx >> 1, area->height, area->width >> 1);
 284}
 285
 286static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
 287        struct matrox_fb_info *minfo = info2minfo(info);
 288
 289        matrox_accel_bmove(minfo, minfo->fbcon.var.xres_virtual, area->sy, area->sx, area->dy, area->dx, area->height, area->width);
 290}
 291
 292static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color,
 293                                 int sy, int sx, int height, int width)
 294{
 295        CRITFLAGS
 296
 297        DBG(__func__)
 298
 299        CRITBEGIN
 300
 301        mga_fifo(5);
 302        mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE);
 303        mga_outl(M_FCOL, color);
 304        mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
 305        mga_ydstlen(sy, height);
 306        WaitTillIdle();
 307
 308        CRITEND
 309}
 310
 311static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
 312        struct matrox_fb_info *minfo = info2minfo(info);
 313
 314        switch (rect->rop) {
 315                case ROP_COPY:
 316                        matroxfb_accel_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
 317                        break;
 318        }
 319}
 320
 321static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx,
 322                                int sy, int sx, int height, int width)
 323{
 324        int whattodo;
 325        CRITFLAGS
 326
 327        DBG(__func__)
 328
 329        CRITBEGIN
 330
 331        whattodo = 0;
 332        if (sx & 1) {
 333                sx ++;
 334                if (!width) return;
 335                width --;
 336                whattodo = 1;
 337        }
 338        if (width & 1) {
 339                whattodo |= 2;
 340        }
 341        width >>= 1;
 342        sx >>= 1;
 343        if (width) {
 344                mga_fifo(5);
 345                mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2);
 346                mga_outl(M_FCOL, bgx);
 347                mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
 348                mga_outl(M_YDST, sy * minfo->fbcon.var.xres_virtual >> 6);
 349                mga_outl(M_LEN | M_EXEC, height);
 350                WaitTillIdle();
 351        }
 352        if (whattodo) {
 353                u_int32_t step = minfo->fbcon.var.xres_virtual >> 1;
 354                vaddr_t vbase = minfo->video.vbase;
 355                if (whattodo & 1) {
 356                        unsigned int uaddr = sy * step + sx - 1;
 357                        u_int32_t loop;
 358                        u_int8_t bgx2 = bgx & 0xF0;
 359                        for (loop = height; loop > 0; loop --) {
 360                                mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
 361                                uaddr += step;
 362                        }
 363                }
 364                if (whattodo & 2) {
 365                        unsigned int uaddr = sy * step + sx + width;
 366                        u_int32_t loop;
 367                        u_int8_t bgx2 = bgx & 0x0F;
 368                        for (loop = height; loop > 0; loop --) {
 369                                mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
 370                                uaddr += step;
 371                        }
 372                }
 373        }
 374
 375        CRITEND
 376}
 377
 378static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
 379        struct matrox_fb_info *minfo = info2minfo(info);
 380
 381        switch (rect->rop) {
 382                case ROP_COPY:
 383                        matroxfb_cfb4_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
 384                        break;
 385        }
 386}
 387
 388static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx,
 389                                    u_int32_t bgx, const u_int8_t *chardata,
 390                                    int width, int height, int yy, int xx)
 391{
 392        u_int32_t step;
 393        u_int32_t ydstlen;
 394        u_int32_t xlen;
 395        u_int32_t ar0;
 396        u_int32_t charcell;
 397        u_int32_t fxbndry;
 398        vaddr_t mmio;
 399        int easy;
 400        CRITFLAGS
 401
 402        DBG_HEAVY(__func__);
 403
 404        step = (width + 7) >> 3;
 405        charcell = height * step;
 406        xlen = (charcell + 3) & ~3;
 407        ydstlen = (yy << 16) | height;
 408        if (width == step << 3) {
 409                ar0 = height * width - 1;
 410                easy = 1;
 411        } else {
 412                ar0 = width - 1;
 413                easy = 0;
 414        }
 415
 416        CRITBEGIN
 417
 418        mga_fifo(3);
 419        if (easy)
 420                mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
 421        else
 422                mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
 423        mga_outl(M_FCOL, fgx);
 424        mga_outl(M_BCOL, bgx);
 425        fxbndry = ((xx + width - 1) << 16) | xx;
 426        mmio = minfo->mmio.vbase;
 427
 428        mga_fifo(6);
 429        mga_writel(mmio, M_FXBNDRY, fxbndry);
 430        mga_writel(mmio, M_AR0, ar0);
 431        mga_writel(mmio, M_AR3, 0);
 432        if (easy) {
 433                mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
 434                mga_memcpy_toio(mmio, chardata, xlen);
 435        } else {
 436                mga_writel(mmio, M_AR5, 0);
 437                mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
 438                if ((step & 3) == 0) {
 439                        /* Great. Source has 32bit aligned lines, so we can feed them
 440                           directly to the accelerator. */
 441                        mga_memcpy_toio(mmio, chardata, charcell);
 442                } else if (step == 1) {
 443                        /* Special case for 1..8bit widths */
 444                        while (height--) {
 445#if defined(__BIG_ENDIAN)
 446                                fb_writel((*chardata) << 24, mmio.vaddr);
 447#else
 448                                fb_writel(*chardata, mmio.vaddr);
 449#endif
 450                                chardata++;
 451                        }
 452                } else if (step == 2) {
 453                        /* Special case for 9..15bit widths */
 454                        while (height--) {
 455#if defined(__BIG_ENDIAN)
 456                                fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
 457#else
 458                                fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
 459#endif
 460                                chardata += 2;
 461                        }
 462                } else {
 463                        /* Tell... well, why bother... */
 464                        while (height--) {
 465                                size_t i;
 466                                
 467                                for (i = 0; i < step; i += 4) {
 468                                        /* Hope that there are at least three readable bytes beyond the end of bitmap */
 469                                        fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
 470                                }
 471                                chardata += step;
 472                        }
 473                }
 474        }
 475        WaitTillIdle();
 476        CRITEND
 477}
 478
 479
 480static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
 481        struct matrox_fb_info *minfo = info2minfo(info);
 482
 483        DBG_HEAVY(__func__);
 484
 485        if (image->depth == 1) {
 486                u_int32_t fgx, bgx;
 487
 488                fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
 489                bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color];
 490                matroxfb_1bpp_imageblit(minfo, fgx, bgx, image->data, image->width, image->height, image->dy, image->dx);
 491        } else {
 492                /* Danger! image->depth is useless: logo painting code always
 493                   passes framebuffer color depth here, although logo data are
 494                   always 8bpp and info->pseudo_palette is changed to contain
 495                   logo palette to be used (but only for true/direct-color... sic...).
 496                   So do it completely in software... */
 497                cfb_imageblit(info, image);
 498        }
 499}
 500
 501MODULE_LICENSE("GPL");
 502