Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
489 giacomo 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 writting this driver)
74
 *
75
 *               FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
76
 *
77
 */
78
 
79
#include <linuxcomp.h>
80
 
81
#include "matroxfb_accel.h"
82
#include "matroxfb_DAC1064.h"
83
#include "matroxfb_Ti3026.h"
84
#include "matroxfb_misc.h"
85
 
86
#define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels)
87
 
88
#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
89
 
90
static inline void matrox_cfb4_pal(u_int32_t* pal) {
91
        unsigned int i;
92
 
93
        for (i = 0; i < 16; i++) {
94
                pal[i] = i * 0x11111111U;
95
        }
96
        pal[i] = 0xFFFFFFFF;
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
        pal[i] = 0x0F0F0F0F;
106
}
107
 
108
static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area);
109
static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
110
static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image);
111
static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
112
static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area);
113
 
114
void matrox_cfbX_init(WPMINFO2) {
115
        u_int32_t maccess;
116
        u_int32_t mpitch;
117
        u_int32_t mopmode;
118
        int accel;
119
 
120
        DBG(__FUNCTION__)
121
 
122
        mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual;
123
 
124
        ACCESS_FBINFO(fbops).fb_copyarea = cfb_copyarea;
125
        ACCESS_FBINFO(fbops).fb_fillrect = cfb_fillrect;
126
        ACCESS_FBINFO(fbops).fb_imageblit = cfb_imageblit;
127
        ACCESS_FBINFO(fbops).fb_cursor = soft_cursor;
128
 
129
        accel = (ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT;
130
 
131
        switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
132
                case 4:         maccess = 0x00000000;   /* accelerate as 8bpp video */
133
                                mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
134
                                mopmode = M_OPMODE_4BPP;
135
                                matrox_cfb4_pal(ACCESS_FBINFO(cmap));
136
                                if (accel && !(mpitch & 1)) {
137
                                        ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_cfb4_copyarea;
138
                                        ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_cfb4_fillrect;
139
                                }
140
                                break;
141
                case 8:         maccess = 0x00000000;
142
                                mopmode = M_OPMODE_8BPP;
143
                                matrox_cfb8_pal(ACCESS_FBINFO(cmap));
144
                                if (accel) {
145
                                        ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
146
                                        ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
147
                                        ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
148
                                }
149
                                break;
150
                case 16:        if (ACCESS_FBINFO(fbcon).var.green.length == 5) {
151
                                        maccess = 0xC0000001;
152
                                        ACCESS_FBINFO(cmap[16]) = 0x7FFF7FFF;
153
                                } else {
154
                                        maccess = 0x40000001;
155
                                        ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
156
                                }
157
                                mopmode = M_OPMODE_16BPP;
158
                                if (accel) {
159
                                        ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
160
                                        ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
161
                                        ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
162
                                }
163
                                break;
164
                case 24:        maccess = 0x00000003;
165
                                mopmode = M_OPMODE_24BPP;
166
                                ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
167
                                if (accel) {
168
                                        ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
169
                                        ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
170
                                        ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
171
                                }
172
                                break;
173
                case 32:        maccess = 0x00000002;
174
                                mopmode = M_OPMODE_32BPP;
175
                                ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
176
                                if (accel) {
177
                                        ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
178
                                        ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
179
                                        ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
180
                                }
181
                                break;
182
                default:        maccess = 0x00000000;
183
                                mopmode = 0x00000000;
184
                                break;  /* turn off acceleration!!! */
185
        }
186
        mga_fifo(8);
187
        mga_outl(M_PITCH, mpitch);
188
        mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
189
        if (ACCESS_FBINFO(capable.plnwt))
190
                mga_outl(M_PLNWT, -1);
191
        if (ACCESS_FBINFO(capable.srcorg)) {
192
                mga_outl(M_SRCORG, 0);
193
                mga_outl(M_DSTORG, 0);
194
        }
195
        mga_outl(M_OPMODE, mopmode);
196
        mga_outl(M_CXBNDRY, 0xFFFF0000);
197
        mga_outl(M_YTOP, 0);
198
        mga_outl(M_YBOT, 0x01FFFFFF);
199
        mga_outl(M_MACCESS, maccess);
200
        ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
201
        if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
202
        ACCESS_FBINFO(accel.m_opmode) = mopmode;
203
}
204
 
205
EXPORT_SYMBOL(matrox_cfbX_init);
206
 
207
static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) {
208
        int start, end;
209
        CRITFLAGS
210
 
211
        DBG(__FUNCTION__)
212
 
213
        CRITBEGIN
214
 
215
        if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
216
                mga_fifo(2);
217
                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
218
                         M_DWG_BFCOL | M_DWG_REPLACE);
219
                mga_outl(M_AR5, vxres);
220
                width--;
221
                start = sy*vxres+sx+curr_ydstorg(MINFO);
222
                end = start+width;
223
        } else {
224
                mga_fifo(3);
225
                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
226
                mga_outl(M_SGN, 5);
227
                mga_outl(M_AR5, -vxres);
228
                width--;
229
                end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO);
230
                start = end+width;
231
                dy += height-1;
232
        }
233
        mga_fifo(4);
234
        mga_outl(M_AR0, end);
235
        mga_outl(M_AR3, start);
236
        mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
237
        mga_ydstlen(dy, height);
238
        WaitTillIdle();
239
 
240
        CRITEND
241
}
242
 
243
static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) {
244
        int start, end;
245
        CRITFLAGS
246
 
247
        DBG(__FUNCTION__)
248
 
249
        CRITBEGIN
250
 
251
        if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
252
                mga_fifo(2);
253
                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
254
                        M_DWG_BFCOL | M_DWG_REPLACE);
255
                mga_outl(M_AR5, vxres);
256
                width--;
257
                start = sy*vxres+sx+curr_ydstorg(MINFO);
258
                end = start+width;
259
        } else {
260
                mga_fifo(3);
261
                mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
262
                mga_outl(M_SGN, 5);
263
                mga_outl(M_AR5, -vxres);
264
                width--;
265
                end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO);
266
                start = end+width;
267
                dy += height-1;
268
        }
269
        mga_fifo(5);
270
        mga_outl(M_AR0, end);
271
        mga_outl(M_AR3, start);
272
        mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
273
        mga_outl(M_YDST, dy*vxres >> 5);
274
        mga_outl(M_LEN | M_EXEC, height);
275
        WaitTillIdle();
276
 
277
        CRITEND
278
}
279
 
280
static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
281
        MINFO_FROM_INFO(info);
282
 
283
        if ((area->sx | area->dx | area->width) & 1)
284
                cfb_copyarea(info, area);
285
        else
286
                matrox_accel_bmove_lin(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual) >> 1, area->sy, area->sx >> 1, area->dy, area->dx >> 1, area->height, area->width >> 1);
287
}
288
 
289
static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
290
        MINFO_FROM_INFO(info);
291
 
292
        matrox_accel_bmove(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual), area->sy, area->sx, area->dy, area->dx, area->height, area->width);
293
}
294
 
295
static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int height,
296
                int width) {
297
        CRITFLAGS
298
 
299
        DBG(__FUNCTION__)
300
 
301
        CRITBEGIN
302
 
303
        mga_fifo(5);
304
        mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
305
        mga_outl(M_FCOL, color);
306
        mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
307
        mga_ydstlen(sy, height);
308
        WaitTillIdle();
309
 
310
        CRITEND
311
}
312
 
313
static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
314
        MINFO_FROM_INFO(info);
315
 
316
        switch (rect->rop) {
317
                case ROP_COPY:
318
                        matroxfb_accel_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
319
                        break;
320
        }
321
}
322
 
323
static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int height, int width) {
324
        int whattodo;
325
        CRITFLAGS
326
 
327
        DBG(__FUNCTION__)
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, ACCESS_FBINFO(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 * ACCESS_FBINFO(fbcon).var.xres_virtual >> 6);
349
                mga_outl(M_LEN | M_EXEC, height);
350
                WaitTillIdle();
351
        }
352
        if (whattodo) {
353
                u_int32_t step = ACCESS_FBINFO(fbcon).var.xres_virtual >> 1;
354
                vaddr_t vbase = ACCESS_FBINFO(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
 
378
static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
379
        MINFO_FROM_INFO(info);
380
 
381
        switch (rect->rop) {
382
                case ROP_COPY:
383
                        matroxfb_cfb4_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
384
                        break;
385
        }
386
}
387
 
388
static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx,
389
                const u_int8_t* chardata, int width, int height, int yy, int xx) {
390
        u_int32_t step;
391
        u_int32_t ydstlen;
392
        u_int32_t xlen;
393
        u_int32_t ar0;
394
        u_int32_t charcell;
395
        u_int32_t fxbndry;
396
        vaddr_t mmio;
397
        int easy;
398
        CRITFLAGS
399
 
400
        DBG_HEAVY(__FUNCTION__);
401
 
402
        step = (width + 7) >> 3;
403
        charcell = height * step;
404
        xlen = (charcell + 3) & ~3;
405
        ydstlen = (yy << 16) | height;
406
        if (width == step << 3) {
407
                ar0 = height * width - 1;
408
                easy = 1;
409
        } else {
410
                ar0 = width - 1;
411
                easy = 0;
412
        }
413
 
414
        CRITBEGIN
415
 
416
#ifdef __BIG_ENDIAN
417
        WaitTillIdle();
418
        mga_outl(M_OPMODE, M_OPMODE_8BPP);
419
#else
420
        mga_fifo(3);
421
#endif
422
        if (easy)
423
                mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
424
        else
425
                mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
426
        mga_outl(M_FCOL, fgx);
427
        mga_outl(M_BCOL, bgx);
428
        fxbndry = ((xx + width - 1) << 16) | xx;
429
        mmio = ACCESS_FBINFO(mmio.vbase);
430
 
431
        mga_fifo(6);
432
        mga_writel(mmio, M_FXBNDRY, fxbndry);
433
        mga_writel(mmio, M_AR0, ar0);
434
        mga_writel(mmio, M_AR3, 0);
435
        if (easy) {
436
                mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
437
                mga_memcpy_toio(mmio, 0, chardata, xlen);
438
        } else {
439
                mga_writel(mmio, M_AR5, 0);
440
                mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
441
                if ((step & 3) == 0) {
442
                        /* Great. Source has 32bit aligned lines, so we can feed them
443
                           directly to the accelerator. */
444
                        mga_memcpy_toio(mmio, 0, chardata, charcell);
445
                } else if (step == 1) {
446
                        /* Special case for 1..8bit widths */
447
                        while (height--) {
448
#ifdef __LITTLE_ENDIAN
449
                                mga_writel(mmio, 0, *chardata);
450
#else
451
                                mga_writel(mmio, 0, (*chardata) << 24);
452
#endif
453
                                chardata++;
454
                        }
455
                } else if (step == 2) {
456
                        /* Special case for 9..15bit widths */
457
                        while (height--) {
458
#ifdef __LITTLE_ENDIAN
459
                                mga_writel(mmio, 0, *(u_int16_t*)chardata);
460
#else
461
                                mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16);
462
#endif
463
                                chardata += 2;
464
                        }
465
                } else {
466
                        /* Tell... well, why bother... */
467
                        while (height--) {
468
                                size_t i;
469
 
470
                                for (i = 0; i < step; i += 4) {
471
                                        /* Hope that there are at least three readable bytes beyond the end of bitmap */
472
                                        mga_writel(mmio, 0, get_unaligned((u_int32_t*)(chardata + i)));
473
                                }
474
                                chardata += step;
475
                        }
476
                }
477
        }
478
        WaitTillIdle();
479
#ifdef __BIG_ENDIAN
480
        mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
481
#endif
482
        CRITEND
483
}
484
 
485
 
486
static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
487
        MINFO_FROM_INFO(info);
488
 
489
        DBG_HEAVY(__FUNCTION__);
490
 
491
        if (image->depth == 0) {
492
                u_int32_t fgx, bgx;
493
 
494
                fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
495
                bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color];
496
                matroxfb_1bpp_imageblit(PMINFO fgx, bgx, image->data, image->width, image->height, image->dy, image->dx);
497
        } else {
498
                /* Danger! image->depth is useless: logo painting code always
499
                   passes framebuffer color depth here, although logo data are
500
                   always 8bpp and info->pseudo_palette is changed to contain
501
                   logo palette to be used (but only for true/direct-color... sic...).
502
                   So do it completely in software... */
503
                cfb_imageblit(info, image);
504
        }
505
}
506
 
507
MODULE_LICENSE("GPL");