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