linux/drivers/video/fbdev/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        minfo->accel.m_access = maccess;
 196        minfo->accel.m_pitch = mpitch;
 197}
 198
 199EXPORT_SYMBOL(matrox_cfbX_init);
 200
 201static void matrox_accel_restore_maccess(struct matrox_fb_info *minfo)
 202{
 203        mga_outl(M_MACCESS, minfo->accel.m_access);
 204        mga_outl(M_PITCH, minfo->accel.m_pitch);
 205}
 206
 207static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
 208                               int sx, int dy, int dx, int height, int width)
 209{
 210        int start, end;
 211        CRITFLAGS
 212
 213        DBG(__func__)
 214
 215        CRITBEGIN
 216
 217        if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
 218                mga_fifo(4);
 219                matrox_accel_restore_maccess(minfo);
 220                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
 221                         M_DWG_BFCOL | M_DWG_REPLACE);
 222                mga_outl(M_AR5, vxres);
 223                width--;
 224                start = sy*vxres+sx+curr_ydstorg(minfo);
 225                end = start+width;
 226        } else {
 227                mga_fifo(5);
 228                matrox_accel_restore_maccess(minfo);
 229                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
 230                mga_outl(M_SGN, 5);
 231                mga_outl(M_AR5, -vxres);
 232                width--;
 233                end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
 234                start = end+width;
 235                dy += height-1;
 236        }
 237        mga_fifo(6);
 238        matrox_accel_restore_maccess(minfo);
 239        mga_outl(M_AR0, end);
 240        mga_outl(M_AR3, start);
 241        mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
 242        mga_ydstlen(dy, height);
 243        WaitTillIdle();
 244
 245        CRITEND
 246}
 247
 248static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres,
 249                                   int sy, int sx, int dy, int dx, int height,
 250                                   int width)
 251{
 252        int start, end;
 253        CRITFLAGS
 254
 255        DBG(__func__)
 256
 257        CRITBEGIN
 258
 259        if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
 260                mga_fifo(4);
 261                matrox_accel_restore_maccess(minfo);
 262                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
 263                        M_DWG_BFCOL | M_DWG_REPLACE);
 264                mga_outl(M_AR5, vxres);
 265                width--;
 266                start = sy*vxres+sx+curr_ydstorg(minfo);
 267                end = start+width;
 268        } else {
 269                mga_fifo(5);
 270                matrox_accel_restore_maccess(minfo);
 271                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
 272                mga_outl(M_SGN, 5);
 273                mga_outl(M_AR5, -vxres);
 274                width--;
 275                end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
 276                start = end+width;
 277                dy += height-1;
 278        }
 279        mga_fifo(7);
 280        matrox_accel_restore_maccess(minfo);
 281        mga_outl(M_AR0, end);
 282        mga_outl(M_AR3, start);
 283        mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
 284        mga_outl(M_YDST, dy*vxres >> 5);
 285        mga_outl(M_LEN | M_EXEC, height);
 286        WaitTillIdle();
 287
 288        CRITEND
 289}
 290
 291static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
 292        struct matrox_fb_info *minfo = info2minfo(info);
 293
 294        if ((area->sx | area->dx | area->width) & 1)
 295                cfb_copyarea(info, area);
 296        else
 297                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);
 298}
 299
 300static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
 301        struct matrox_fb_info *minfo = info2minfo(info);
 302
 303        matrox_accel_bmove(minfo, minfo->fbcon.var.xres_virtual, area->sy, area->sx, area->dy, area->dx, area->height, area->width);
 304}
 305
 306static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color,
 307                                 int sy, int sx, int height, int width)
 308{
 309        CRITFLAGS
 310
 311        DBG(__func__)
 312
 313        CRITBEGIN
 314
 315        mga_fifo(7);
 316        matrox_accel_restore_maccess(minfo);
 317        mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE);
 318        mga_outl(M_FCOL, color);
 319        mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
 320        mga_ydstlen(sy, height);
 321        WaitTillIdle();
 322
 323        CRITEND
 324}
 325
 326static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
 327        struct matrox_fb_info *minfo = info2minfo(info);
 328
 329        switch (rect->rop) {
 330                case ROP_COPY:
 331                        matroxfb_accel_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
 332                        break;
 333        }
 334}
 335
 336static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx,
 337                                int sy, int sx, int height, int width)
 338{
 339        int whattodo;
 340        CRITFLAGS
 341
 342        DBG(__func__)
 343
 344        CRITBEGIN
 345
 346        whattodo = 0;
 347        if (sx & 1) {
 348                sx ++;
 349                if (!width) return;
 350                width --;
 351                whattodo = 1;
 352        }
 353        if (width & 1) {
 354                whattodo |= 2;
 355        }
 356        width >>= 1;
 357        sx >>= 1;
 358        if (width) {
 359                mga_fifo(7);
 360                matrox_accel_restore_maccess(minfo);
 361                mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2);
 362                mga_outl(M_FCOL, bgx);
 363                mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
 364                mga_outl(M_YDST, sy * minfo->fbcon.var.xres_virtual >> 6);
 365                mga_outl(M_LEN | M_EXEC, height);
 366                WaitTillIdle();
 367        }
 368        if (whattodo) {
 369                u_int32_t step = minfo->fbcon.var.xres_virtual >> 1;
 370                vaddr_t vbase = minfo->video.vbase;
 371                if (whattodo & 1) {
 372                        unsigned int uaddr = sy * step + sx - 1;
 373                        u_int32_t loop;
 374                        u_int8_t bgx2 = bgx & 0xF0;
 375                        for (loop = height; loop > 0; loop --) {
 376                                mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
 377                                uaddr += step;
 378                        }
 379                }
 380                if (whattodo & 2) {
 381                        unsigned int uaddr = sy * step + sx + width;
 382                        u_int32_t loop;
 383                        u_int8_t bgx2 = bgx & 0x0F;
 384                        for (loop = height; loop > 0; loop --) {
 385                                mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
 386                                uaddr += step;
 387                        }
 388                }
 389        }
 390
 391        CRITEND
 392}
 393
 394static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
 395        struct matrox_fb_info *minfo = info2minfo(info);
 396
 397        switch (rect->rop) {
 398                case ROP_COPY:
 399                        matroxfb_cfb4_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
 400                        break;
 401        }
 402}
 403
 404static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx,
 405                                    u_int32_t bgx, const u_int8_t *chardata,
 406                                    int width, int height, int yy, int xx)
 407{
 408        u_int32_t step;
 409        u_int32_t ydstlen;
 410        u_int32_t xlen;
 411        u_int32_t ar0;
 412        u_int32_t charcell;
 413        u_int32_t fxbndry;
 414        vaddr_t mmio;
 415        int easy;
 416        CRITFLAGS
 417
 418        DBG_HEAVY(__func__);
 419
 420        step = (width + 7) >> 3;
 421        charcell = height * step;
 422        xlen = (charcell + 3) & ~3;
 423        ydstlen = (yy << 16) | height;
 424        if (width == step << 3) {
 425                ar0 = height * width - 1;
 426                easy = 1;
 427        } else {
 428                ar0 = width - 1;
 429                easy = 0;
 430        }
 431
 432        CRITBEGIN
 433
 434        mga_fifo(5);
 435        matrox_accel_restore_maccess(minfo);
 436        if (easy)
 437                mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
 438        else
 439                mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
 440        mga_outl(M_FCOL, fgx);
 441        mga_outl(M_BCOL, bgx);
 442        fxbndry = ((xx + width - 1) << 16) | xx;
 443        mmio = minfo->mmio.vbase;
 444
 445        mga_fifo(8);
 446        matrox_accel_restore_maccess(minfo);
 447        mga_writel(mmio, M_FXBNDRY, fxbndry);
 448        mga_writel(mmio, M_AR0, ar0);
 449        mga_writel(mmio, M_AR3, 0);
 450        if (easy) {
 451                mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
 452                mga_memcpy_toio(mmio, chardata, xlen);
 453        } else {
 454                mga_writel(mmio, M_AR5, 0);
 455                mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
 456                if ((step & 3) == 0) {
 457                        /* Great. Source has 32bit aligned lines, so we can feed them
 458                           directly to the accelerator. */
 459                        mga_memcpy_toio(mmio, chardata, charcell);
 460                } else if (step == 1) {
 461                        /* Special case for 1..8bit widths */
 462                        while (height--) {
 463#if defined(__BIG_ENDIAN)
 464                                fb_writel((*chardata) << 24, mmio.vaddr);
 465#else
 466                                fb_writel(*chardata, mmio.vaddr);
 467#endif
 468                                chardata++;
 469                        }
 470                } else if (step == 2) {
 471                        /* Special case for 9..15bit widths */
 472                        while (height--) {
 473#if defined(__BIG_ENDIAN)
 474                                fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
 475#else
 476                                fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
 477#endif
 478                                chardata += 2;
 479                        }
 480                } else {
 481                        /* Tell... well, why bother... */
 482                        while (height--) {
 483                                size_t i;
 484                                
 485                                for (i = 0; i < step; i += 4) {
 486                                        /* Hope that there are at least three readable bytes beyond the end of bitmap */
 487                                        fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
 488                                }
 489                                chardata += step;
 490                        }
 491                }
 492        }
 493        WaitTillIdle();
 494        CRITEND
 495}
 496
 497
 498static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
 499        struct matrox_fb_info *minfo = info2minfo(info);
 500
 501        DBG_HEAVY(__func__);
 502
 503        if (image->depth == 1) {
 504                u_int32_t fgx, bgx;
 505
 506                fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
 507                bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color];
 508                matroxfb_1bpp_imageblit(minfo, fgx, bgx, image->data, image->width, image->height, image->dy, image->dx);
 509        } else {
 510                /* Danger! image->depth is useless: logo painting code always
 511                   passes framebuffer color depth here, although logo data are
 512                   always 8bpp and info->pseudo_palette is changed to contain
 513                   logo palette to be used (but only for true/direct-color... sic...).
 514                   So do it completely in software... */
 515                cfb_imageblit(info, image);
 516        }
 517}
 518
 519MODULE_LICENSE("GPL");
 520