0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 #include "matroxfb_accel.h"
0081 #include "matroxfb_DAC1064.h"
0082 #include "matroxfb_Ti3026.h"
0083 #include "matroxfb_misc.h"
0084
0085 #define curr_ydstorg(x) ((x)->curr.ydstorg.pixels)
0086
0087 #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
0088
0089 static inline void matrox_cfb4_pal(u_int32_t* pal) {
0090 unsigned int i;
0091
0092 for (i = 0; i < 16; i++) {
0093 pal[i] = i * 0x11111111U;
0094 }
0095 }
0096
0097 static inline void matrox_cfb8_pal(u_int32_t* pal) {
0098 unsigned int i;
0099
0100 for (i = 0; i < 16; i++) {
0101 pal[i] = i * 0x01010101U;
0102 }
0103 }
0104
0105 static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area);
0106 static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
0107 static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image);
0108 static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
0109 static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area);
0110
0111 void matrox_cfbX_init(struct matrox_fb_info *minfo)
0112 {
0113 u_int32_t maccess;
0114 u_int32_t mpitch;
0115 u_int32_t mopmode;
0116 int accel;
0117
0118 DBG(__func__)
0119
0120 mpitch = minfo->fbcon.var.xres_virtual;
0121
0122 minfo->fbops.fb_copyarea = cfb_copyarea;
0123 minfo->fbops.fb_fillrect = cfb_fillrect;
0124 minfo->fbops.fb_imageblit = cfb_imageblit;
0125 minfo->fbops.fb_cursor = NULL;
0126
0127 accel = (minfo->fbcon.var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT;
0128
0129 switch (minfo->fbcon.var.bits_per_pixel) {
0130 case 4: maccess = 0x00000000;
0131 mpitch = (mpitch >> 1) | 0x8000;
0132 mopmode = M_OPMODE_4BPP;
0133 matrox_cfb4_pal(minfo->cmap);
0134 if (accel && !(mpitch & 1)) {
0135 minfo->fbops.fb_copyarea = matroxfb_cfb4_copyarea;
0136 minfo->fbops.fb_fillrect = matroxfb_cfb4_fillrect;
0137 }
0138 break;
0139 case 8: maccess = 0x00000000;
0140 mopmode = M_OPMODE_8BPP;
0141 matrox_cfb8_pal(minfo->cmap);
0142 if (accel) {
0143 minfo->fbops.fb_copyarea = matroxfb_copyarea;
0144 minfo->fbops.fb_fillrect = matroxfb_fillrect;
0145 minfo->fbops.fb_imageblit = matroxfb_imageblit;
0146 }
0147 break;
0148 case 16: if (minfo->fbcon.var.green.length == 5)
0149 maccess = 0xC0000001;
0150 else
0151 maccess = 0x40000001;
0152 mopmode = M_OPMODE_16BPP;
0153 if (accel) {
0154 minfo->fbops.fb_copyarea = matroxfb_copyarea;
0155 minfo->fbops.fb_fillrect = matroxfb_fillrect;
0156 minfo->fbops.fb_imageblit = matroxfb_imageblit;
0157 }
0158 break;
0159 case 24: maccess = 0x00000003;
0160 mopmode = M_OPMODE_24BPP;
0161 if (accel) {
0162 minfo->fbops.fb_copyarea = matroxfb_copyarea;
0163 minfo->fbops.fb_fillrect = matroxfb_fillrect;
0164 minfo->fbops.fb_imageblit = matroxfb_imageblit;
0165 }
0166 break;
0167 case 32: maccess = 0x00000002;
0168 mopmode = M_OPMODE_32BPP;
0169 if (accel) {
0170 minfo->fbops.fb_copyarea = matroxfb_copyarea;
0171 minfo->fbops.fb_fillrect = matroxfb_fillrect;
0172 minfo->fbops.fb_imageblit = matroxfb_imageblit;
0173 }
0174 break;
0175 default: maccess = 0x00000000;
0176 mopmode = 0x00000000;
0177 break;
0178 }
0179 mga_fifo(8);
0180 mga_outl(M_PITCH, mpitch);
0181 mga_outl(M_YDSTORG, curr_ydstorg(minfo));
0182 if (minfo->capable.plnwt)
0183 mga_outl(M_PLNWT, -1);
0184 if (minfo->capable.srcorg) {
0185 mga_outl(M_SRCORG, 0);
0186 mga_outl(M_DSTORG, 0);
0187 }
0188 mga_outl(M_OPMODE, mopmode);
0189 mga_outl(M_CXBNDRY, 0xFFFF0000);
0190 mga_outl(M_YTOP, 0);
0191 mga_outl(M_YBOT, 0x01FFFFFF);
0192 mga_outl(M_MACCESS, maccess);
0193 minfo->accel.m_dwg_rect = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
0194 if (isMilleniumII(minfo)) minfo->accel.m_dwg_rect |= M_DWG_TRANSC;
0195 minfo->accel.m_opmode = mopmode;
0196 minfo->accel.m_access = maccess;
0197 minfo->accel.m_pitch = mpitch;
0198 }
0199
0200 EXPORT_SYMBOL(matrox_cfbX_init);
0201
0202 static void matrox_accel_restore_maccess(struct matrox_fb_info *minfo)
0203 {
0204 mga_outl(M_MACCESS, minfo->accel.m_access);
0205 mga_outl(M_PITCH, minfo->accel.m_pitch);
0206 }
0207
0208 static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
0209 int sx, int dy, int dx, int height, int width)
0210 {
0211 int start, end;
0212 CRITFLAGS
0213
0214 DBG(__func__)
0215
0216 CRITBEGIN
0217
0218 if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
0219 mga_fifo(4);
0220 matrox_accel_restore_maccess(minfo);
0221 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
0222 M_DWG_BFCOL | M_DWG_REPLACE);
0223 mga_outl(M_AR5, vxres);
0224 width--;
0225 start = sy*vxres+sx+curr_ydstorg(minfo);
0226 end = start+width;
0227 } else {
0228 mga_fifo(5);
0229 matrox_accel_restore_maccess(minfo);
0230 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
0231 mga_outl(M_SGN, 5);
0232 mga_outl(M_AR5, -vxres);
0233 width--;
0234 end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
0235 start = end+width;
0236 dy += height-1;
0237 }
0238 mga_fifo(6);
0239 matrox_accel_restore_maccess(minfo);
0240 mga_outl(M_AR0, end);
0241 mga_outl(M_AR3, start);
0242 mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
0243 mga_ydstlen(dy, height);
0244 WaitTillIdle();
0245
0246 CRITEND
0247 }
0248
0249 static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres,
0250 int sy, int sx, int dy, int dx, int height,
0251 int width)
0252 {
0253 int start, end;
0254 CRITFLAGS
0255
0256 DBG(__func__)
0257
0258 CRITBEGIN
0259
0260 if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
0261 mga_fifo(4);
0262 matrox_accel_restore_maccess(minfo);
0263 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
0264 M_DWG_BFCOL | M_DWG_REPLACE);
0265 mga_outl(M_AR5, vxres);
0266 width--;
0267 start = sy*vxres+sx+curr_ydstorg(minfo);
0268 end = start+width;
0269 } else {
0270 mga_fifo(5);
0271 matrox_accel_restore_maccess(minfo);
0272 mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
0273 mga_outl(M_SGN, 5);
0274 mga_outl(M_AR5, -vxres);
0275 width--;
0276 end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
0277 start = end+width;
0278 dy += height-1;
0279 }
0280 mga_fifo(7);
0281 matrox_accel_restore_maccess(minfo);
0282 mga_outl(M_AR0, end);
0283 mga_outl(M_AR3, start);
0284 mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
0285 mga_outl(M_YDST, dy*vxres >> 5);
0286 mga_outl(M_LEN | M_EXEC, height);
0287 WaitTillIdle();
0288
0289 CRITEND
0290 }
0291
0292 static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
0293 struct matrox_fb_info *minfo = info2minfo(info);
0294
0295 if ((area->sx | area->dx | area->width) & 1)
0296 cfb_copyarea(info, area);
0297 else
0298 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);
0299 }
0300
0301 static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
0302 struct matrox_fb_info *minfo = info2minfo(info);
0303
0304 matrox_accel_bmove(minfo, minfo->fbcon.var.xres_virtual, area->sy, area->sx, area->dy, area->dx, area->height, area->width);
0305 }
0306
0307 static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color,
0308 int sy, int sx, int height, int width)
0309 {
0310 CRITFLAGS
0311
0312 DBG(__func__)
0313
0314 CRITBEGIN
0315
0316 mga_fifo(7);
0317 matrox_accel_restore_maccess(minfo);
0318 mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE);
0319 mga_outl(M_FCOL, color);
0320 mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
0321 mga_ydstlen(sy, height);
0322 WaitTillIdle();
0323
0324 CRITEND
0325 }
0326
0327 static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
0328 struct matrox_fb_info *minfo = info2minfo(info);
0329
0330 switch (rect->rop) {
0331 case ROP_COPY:
0332 matroxfb_accel_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
0333 break;
0334 }
0335 }
0336
0337 static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx,
0338 int sy, int sx, int height, int width)
0339 {
0340 int whattodo;
0341 CRITFLAGS
0342
0343 DBG(__func__)
0344
0345 CRITBEGIN
0346
0347 whattodo = 0;
0348 if (sx & 1) {
0349 sx ++;
0350 if (!width) return;
0351 width --;
0352 whattodo = 1;
0353 }
0354 if (width & 1) {
0355 whattodo |= 2;
0356 }
0357 width >>= 1;
0358 sx >>= 1;
0359 if (width) {
0360 mga_fifo(7);
0361 matrox_accel_restore_maccess(minfo);
0362 mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2);
0363 mga_outl(M_FCOL, bgx);
0364 mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
0365 mga_outl(M_YDST, sy * minfo->fbcon.var.xres_virtual >> 6);
0366 mga_outl(M_LEN | M_EXEC, height);
0367 WaitTillIdle();
0368 }
0369 if (whattodo) {
0370 u_int32_t step = minfo->fbcon.var.xres_virtual >> 1;
0371 vaddr_t vbase = minfo->video.vbase;
0372 if (whattodo & 1) {
0373 unsigned int uaddr = sy * step + sx - 1;
0374 u_int32_t loop;
0375 u_int8_t bgx2 = bgx & 0xF0;
0376 for (loop = height; loop > 0; loop --) {
0377 mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
0378 uaddr += step;
0379 }
0380 }
0381 if (whattodo & 2) {
0382 unsigned int uaddr = sy * step + sx + width;
0383 u_int32_t loop;
0384 u_int8_t bgx2 = bgx & 0x0F;
0385 for (loop = height; loop > 0; loop --) {
0386 mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
0387 uaddr += step;
0388 }
0389 }
0390 }
0391
0392 CRITEND
0393 }
0394
0395 static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
0396 struct matrox_fb_info *minfo = info2minfo(info);
0397
0398 switch (rect->rop) {
0399 case ROP_COPY:
0400 matroxfb_cfb4_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
0401 break;
0402 }
0403 }
0404
0405 static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx,
0406 u_int32_t bgx, const u_int8_t *chardata,
0407 int width, int height, int yy, int xx)
0408 {
0409 u_int32_t step;
0410 u_int32_t ydstlen;
0411 u_int32_t xlen;
0412 u_int32_t ar0;
0413 u_int32_t charcell;
0414 u_int32_t fxbndry;
0415 vaddr_t mmio;
0416 int easy;
0417 CRITFLAGS
0418
0419 DBG_HEAVY(__func__);
0420
0421 step = (width + 7) >> 3;
0422 charcell = height * step;
0423 xlen = (charcell + 3) & ~3;
0424 ydstlen = (yy << 16) | height;
0425 if (width == step << 3) {
0426 ar0 = height * width - 1;
0427 easy = 1;
0428 } else {
0429 ar0 = width - 1;
0430 easy = 0;
0431 }
0432
0433 CRITBEGIN
0434
0435 mga_fifo(5);
0436 matrox_accel_restore_maccess(minfo);
0437 if (easy)
0438 mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
0439 else
0440 mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
0441 mga_outl(M_FCOL, fgx);
0442 mga_outl(M_BCOL, bgx);
0443 fxbndry = ((xx + width - 1) << 16) | xx;
0444 mmio = minfo->mmio.vbase;
0445
0446 mga_fifo(8);
0447 matrox_accel_restore_maccess(minfo);
0448 mga_writel(mmio, M_FXBNDRY, fxbndry);
0449 mga_writel(mmio, M_AR0, ar0);
0450 mga_writel(mmio, M_AR3, 0);
0451 if (easy) {
0452 mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
0453 mga_memcpy_toio(mmio, chardata, xlen);
0454 } else {
0455 mga_writel(mmio, M_AR5, 0);
0456 mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
0457 if ((step & 3) == 0) {
0458
0459
0460 mga_memcpy_toio(mmio, chardata, charcell);
0461 } else if (step == 1) {
0462
0463 while (height--) {
0464 #if defined(__BIG_ENDIAN)
0465 fb_writel((*chardata) << 24, mmio.vaddr);
0466 #else
0467 fb_writel(*chardata, mmio.vaddr);
0468 #endif
0469 chardata++;
0470 }
0471 } else if (step == 2) {
0472
0473 while (height--) {
0474 #if defined(__BIG_ENDIAN)
0475 fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
0476 #else
0477 fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
0478 #endif
0479 chardata += 2;
0480 }
0481 } else {
0482
0483 while (height--) {
0484 size_t i;
0485
0486 for (i = 0; i < step; i += 4) {
0487
0488 fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
0489 }
0490 chardata += step;
0491 }
0492 }
0493 }
0494 WaitTillIdle();
0495 CRITEND
0496 }
0497
0498
0499 static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
0500 struct matrox_fb_info *minfo = info2minfo(info);
0501
0502 DBG_HEAVY(__func__);
0503
0504 if (image->depth == 1) {
0505 u_int32_t fgx, bgx;
0506
0507 fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
0508 bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color];
0509 matroxfb_1bpp_imageblit(minfo, fgx, bgx, image->data, image->width, image->height, image->dy, image->dx);
0510 } else {
0511
0512
0513
0514
0515
0516 cfb_imageblit(info, image);
0517 }
0518 }
0519
0520 MODULE_LICENSE("GPL");