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