]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vgamga4xx.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / pc / vgamga4xx.c
1
2 /*
3  * Matrox G200, G400 and G450.
4  * Written by Philippe Anel <xigh@free.fr>
5  *
6  *  2006-08-07 : Minor fix to allow the G200 cards to work fine. YDSTORG is now initialized.
7  *             : Also support for 16 and 24 bit modes is added.
8  *             : by Leonardo Valencia <leoval@anixcorp.com>
9  */
10
11 #include "u.h"
12 #include "../port/lib.h"
13 #include "mem.h"
14 #include "dat.h"
15 #include "fns.h"
16 #include "io.h"
17 #include "../port/error.h"
18
19 #define Image IMAGE
20 #include <draw.h>
21 #include <memdraw.h>
22 #include <cursor.h>
23 #include "screen.h"
24
25 enum {
26         MATROX                  = 0x102B,
27         MGA550                  = 0x2527,
28         MGA4xx                  = 0x0525,
29         MGA200                  = 0x0521,
30
31         FCOL                    = 0x1c24,
32         FXRIGHT                 = 0x1cac,       
33         FXLEFT                  = 0x1ca8,
34         YDST                    = 0x1c90,
35         YLEN                    = 0x1c5c,
36         DWGCTL                  = 0x1c00,
37                 DWG_TRAP                = 0x04,
38                 DWG_BITBLT              = 0x08,
39                 DWG_ILOAD               = 0x09,
40                 DWG_LINEAR              = 0x0080,
41                 DWG_SOLID               = 0x0800,
42                 DWG_ARZERO              = 0x1000,
43                 DWG_SGNZERO             = 0x2000,
44                 DWG_SHIFTZERO   = 0x4000,
45                 DWG_REPLACE             = 0x000C0000,
46                 DWG_BFCOL               = 0x04000000,
47         SRCORG                  = 0x2cb4,
48         PITCH                   = 0x1c8c,
49         DSTORG                  = 0x2cb8,
50         YDSTORG                 = 0x1c94,
51         PLNWRT                  = 0x1c1c,
52         ZORG                    = 0x1c0c,
53         MACCESS                 = 0x1c04,
54         STATUS                  = 0x1e14,
55         FXBNDRY                 = 0x1C84,
56         CXBNDRY                 = 0x1C80,
57         YTOP                    = 0x1C98,
58         YBOT                    = 0x1C9C,
59         YDSTLEN                 = 0x1C88,
60         AR0                             = 0x1C60,
61         AR1                             = 0x1C64,
62         AR2                             = 0x1C68,
63         AR3                             = 0x1C6C,
64         AR4                             = 0x1C70,
65         AR5                             = 0x1C74,
66         SGN                             = 0x1C58,
67                 SGN_LEFT                = 1,
68                 SGN_UP                  = 4,
69
70         GO                              = 0x0100,
71         FIFOSTATUS              = 0x1E10,
72         CACHEFLUSH              = 0x1FFF,
73
74         CRTCEXTIDX              = 0x1FDE,               /* CRTC Extension Index */
75         CRTCEXTDATA             = 0x1FDF,               /* CRTC Extension Data */
76
77         FILL_OPERAND    = 0x800c7804,
78 };
79
80 static void
81 mgawrite8(VGAscr *scr, int index, uchar val)
82 {
83         ((uchar*)scr->mmio)[index] = val;
84 }
85
86 static uchar
87 mgaread8(VGAscr *scr, int index)
88 {
89         return ((uchar*)scr->mmio)[index];
90 }
91
92 static uchar
93 crtcextset(VGAscr *scr, int index, uchar set, uchar clr)
94 {
95         uchar tmp;
96
97         mgawrite8(scr, CRTCEXTIDX, index);
98         tmp = mgaread8(scr, CRTCEXTDATA);
99         mgawrite8(scr, CRTCEXTIDX, index);
100         mgawrite8(scr, CRTCEXTDATA, (tmp & ~clr) | set);
101
102         return tmp;
103 }
104
105 static void
106 mga4xxenable(VGAscr* scr)
107 {
108         Pcidev *pci;
109         int size;
110         int i, n, k;
111         uchar *p;
112         uchar x[16];
113         uchar crtcext3;
114
115         if(scr->mmio)
116                 return;
117
118         pci = scr->pci;
119         if(pci == nil)
120                 return;
121
122         scr->mmio = vmap(pci->mem[1].bar&~0x0F, 16*1024);
123         if(scr->mmio == nil)
124                 return;
125         
126         addvgaseg("mga4xxmmio", pci->mem[1].bar&~0x0F, pci->mem[1].size);
127
128         /* need to map frame buffer here too, so vga can find memory size */
129         if(pci->did == MGA4xx || pci->did == MGA550)
130                 size = 32*MB;
131         else
132                 size = 8*MB;
133         vgalinearaddr(scr, pci->mem[0].bar&~0x0F, size);
134
135         if(scr->paddr){
136
137                 /* Find out how much memory is here, some multiple of 2 MB */
138
139                 /* First Set MGA Mode ... */
140                 crtcext3 = crtcextset(scr, 3, 0x80, 0x00);
141
142                 p = scr->vaddr;
143                 n = (size / MB) / 2;
144                 for(i = 0; i < n; i++){
145                         k = (2*i+1)*MB;
146                         p[k] = 0;
147                         p[k] = i+1;
148                         *((uchar*)scr->mmio + CACHEFLUSH) = 0;
149                         x[i] = p[k];
150                 }
151                 for(i = 1; i < n; i++)
152                         if(x[i] != i+1)
153                                 break;
154                 scr->apsize = 2*i*MB;   /* sketchy */
155                 addvgaseg("mga4xxscreen", scr->paddr, scr->apsize);
156                 crtcextset(scr, 3, crtcext3, 0xff);
157         }
158 }
159
160 enum{
161         Index           = 0x00,         /* Index */
162         Data                    = 0x0A,         /* Data */
163
164         Cxlsb           = 0x0C,         /* Cursor X LSB */
165         Cxmsb           = 0x0D,         /* Cursor X MSB */
166         Cylsb           = 0x0E,         /* Cursor Y LSB */
167         Cymsb           = 0x0F,         /* Cursor Y MSB */
168
169         Icuradrl                = 0x04,         /* Cursor Base Address Low */   
170         Icuradrh                = 0x05,         /* Cursor Base Address High */
171         Icctl                   = 0x06,         /* Indirect Cursor Control */
172 };
173
174 static void
175 dac4xxdisable(VGAscr *scr)
176 {
177         uchar *dac4xx;
178         
179         if(scr->mmio == 0)
180                 return;
181
182         dac4xx = (uchar*)scr->mmio+0x3C00;
183         
184         *(dac4xx+Index) = Icctl;
185         *(dac4xx+Data) = 0x00;
186 }
187
188 static void
189 dac4xxload(VGAscr *scr, Cursor *curs)
190 {
191         int y;
192         uchar *p;
193         uchar *dac4xx;
194
195         if(scr->mmio == 0)
196                 return;
197
198         dac4xx = (uchar*)scr->mmio+0x3C00;
199         
200         dac4xxdisable(scr);
201
202         p = (uchar*)scr->storage;
203         for(y = 0; y < 64; y++){
204                 *p++ = 0; *p++ = 0; *p++ = 0;
205                 *p++ = 0; *p++ = 0; *p++ = 0;
206                 if(y < 16){
207                         *p++ = curs->set[1+y*2];
208                         *p++ = curs->set[y*2];
209                 } else{
210                         *p++ = 0; *p++ = 0;
211                 }
212
213                 *p++ = 0; *p++ = 0; *p++ = 0;
214                 *p++ = 0; *p++ = 0; *p++ = 0;
215                 if(y < 16){
216                         *p++ = curs->set[1+y*2]|curs->clr[1+2*y];
217                         *p++ = curs->set[y*2]|curs->clr[2*y];
218                 } else{
219                         *p++ = 0; *p++ = 0;
220                 }
221         }
222         scr->offset.x = 64 + curs->offset.x;
223         scr->offset.y = 64 + curs->offset.y;
224
225         *(dac4xx+Index) = Icctl;
226         *(dac4xx+Data) = 0x03;
227 }
228
229 static int
230 dac4xxmove(VGAscr *scr, Point p)
231 {
232         int x, y;
233         uchar *dac4xx;
234
235         if(scr->mmio == 0)
236                 return 1;
237
238         dac4xx = (uchar*)scr->mmio + 0x3C00;
239
240         x = p.x + scr->offset.x;
241         y = p.y + scr->offset.y;
242
243         *(dac4xx+Cxlsb) = x & 0xFF;
244         *(dac4xx+Cxmsb) = (x>>8) & 0x0F;
245
246         *(dac4xx+Cylsb) = y & 0xFF;
247         *(dac4xx+Cymsb) = (y>>8) & 0x0F;
248
249         return 0;
250 }
251
252 static void
253 dac4xxenable(VGAscr *scr)
254 {
255         uchar *dac4xx;
256         ulong storage;
257         
258         if(scr->mmio == 0)
259                 return;
260         dac4xx = (uchar*)scr->mmio+0x3C00;
261
262         dac4xxdisable(scr);
263
264         storage = (scr->apsize-4096)&~0x3ff;
265
266         *(dac4xx+Index) = Icuradrl;
267         *(dac4xx+Data) = 0xff & (storage >> 10);
268         *(dac4xx+Index) = Icuradrh;
269         *(dac4xx+Data) = 0xff & (storage >> 18);                
270
271         scr->storage = (ulong)scr->vaddr + storage;
272
273         /* Show X11-Like Cursor */
274         *(dac4xx+Index) = Icctl;
275         *(dac4xx+Data) = 0x03;
276
277         /* Cursor Color 0 : White */
278         *(dac4xx+Index) = 0x08;
279         *(dac4xx+Data)  = 0xff;
280         *(dac4xx+Index) = 0x09;
281         *(dac4xx+Data)  = 0xff;
282         *(dac4xx+Index) = 0x0a;
283         *(dac4xx+Data)  = 0xff;
284
285         /* Cursor Color 1 : Black */
286         *(dac4xx+Index) = 0x0c;
287         *(dac4xx+Data)  = 0x00;
288         *(dac4xx+Index) = 0x0d;
289         *(dac4xx+Data)  = 0x00;
290         *(dac4xx+Index) = 0x0e;
291         *(dac4xx+Data)  = 0x00;
292
293         /* Cursor Color 2 : Red */
294         *(dac4xx+Index) = 0x10;
295         *(dac4xx+Data)  = 0xff;
296         *(dac4xx+Index) = 0x11;
297         *(dac4xx+Data)  = 0x00;
298         *(dac4xx+Index) = 0x12;
299         *(dac4xx+Data)  = 0x00;
300
301         /*
302          * Load, locate and enable the
303          * 64x64 cursor in X11 mode.
304          */
305         dac4xxload(scr, &cursor);
306         dac4xxmove(scr, ZP);
307 }
308
309 static void
310 mga4xxblank(VGAscr *scr, int blank)
311 {
312         char *cp;
313         uchar *mga;
314         uchar seq1, crtcext1;
315         
316         /* blank = 0 -> turn screen on */
317         /* blank = 1 -> turn screen off */
318
319         if(scr->mmio == 0)
320                 return;
321         mga = (uchar*)scr->mmio;        
322
323         if(blank == 0){
324                 seq1 = 0x00;
325                 crtcext1 = 0x00;
326         } else {
327                 seq1 = 0x20;
328                 crtcext1 = 0x10;                        /* Default value ... : standby */
329                 cp = getconf("*dpms");
330                 if(cp){
331                         if(cistrcmp(cp, "standby") == 0)
332                                 crtcext1 = 0x10;
333                         else if(cistrcmp(cp, "suspend") == 0)
334                                 crtcext1 = 0x20;
335                         else if(cistrcmp(cp, "off") == 0)
336                                 crtcext1 = 0x30;
337                 }
338         }
339
340         *(mga + 0x1fc4) = 1;
341         seq1 |= *(mga + 0x1fc5) & ~0x20;
342         *(mga + 0x1fc5) = seq1;
343
344         *(mga + 0x1fde) = 1;
345         crtcext1 |= *(mga + 0x1fdf) & ~0x30;
346         *(mga + 0x1fdf) = crtcext1;
347 }
348
349 static void
350 mgawrite32(uchar *mga, ulong reg, ulong val)
351 {
352         *((ulong*)(&mga[reg])) = val;
353 }
354
355 static ulong
356 mgaread32(uchar *mga, ulong reg)
357 {
358         return *((ulong*)(&mga[reg]));
359 }
360
361 static void
362 mga_fifo(uchar *mga, uchar n)
363 {
364         ulong t;
365
366 #define Timeout 100
367         for (t = 0; t < Timeout; t++)
368                 if ((mgaread32(mga, FIFOSTATUS) & 0xff) >= n)
369                         break;
370         if (t >= Timeout)
371                 print("mga4xx: fifo timeout");
372 }
373
374 static int
375 mga4xxfill(VGAscr *scr, Rectangle r, ulong color)
376 {
377         uchar *mga;
378
379         if(scr->mmio == 0)
380                 return 0;
381         mga = (uchar*)scr->mmio;
382
383         mga_fifo(mga, 7);
384         mgawrite32(mga, DWGCTL, 0);
385         mgawrite32(mga, FCOL, color);
386         mgawrite32(mga, FXLEFT, r.min.x);
387         mgawrite32(mga, FXRIGHT, r.max.x);
388         mgawrite32(mga, YDST, r.min.y);
389         mgawrite32(mga, YLEN, Dy(r));
390         mgawrite32(mga, DWGCTL + GO, FILL_OPERAND);
391
392         while(mgaread32(mga, STATUS) & 0x00010000)
393                 ;
394
395         return 1;
396 }
397
398 static int
399 mga4xxscroll(VGAscr *scr, Rectangle dr, Rectangle sr)
400 {
401         uchar * mga;
402         int pitch;
403         int width, height;
404         ulong start, end, sgn;
405         Point sp, dp;
406  
407         if(scr->mmio == 0)
408                 return 0;
409         mga = (uchar*)scr->mmio;
410
411         assert(Dx(sr) == Dx(dr) && Dy(sr) == Dy(dr));
412
413         sp = sr.min;
414         dp = dr.min;
415         if(eqpt(sp, dp))
416                 return 1;
417
418         pitch = Dx(scr->gscreen->r);
419         width = Dx(sr);
420         height = Dy(sr);
421         sgn = 0;
422
423         if(dp.y > sp.y && dp.y < sp.y + height){
424                 sp.y += height - 1;
425                 dp.y += height - 1;
426                 sgn |= SGN_UP;
427         }
428
429         width--;
430         start = end = sp.x + (sp.y * pitch);
431
432         if(dp.x > sp.x && dp.x < sp.x + width){
433                 start += width;
434                 sgn |= SGN_LEFT;
435         }
436         else
437                 end += width;
438
439         mga_fifo(mga, 8);
440         mgawrite32(mga, DWGCTL, 0);
441         mgawrite32(mga, SGN, sgn);
442         mgawrite32(mga, AR5, sgn & SGN_UP ? -pitch : pitch);
443         mgawrite32(mga, AR0, end);
444         mgawrite32(mga, AR3, start);
445         mgawrite32(mga, FXBNDRY, ((dp.x + width) << 16) | dp.x);
446         mgawrite32(mga, YDSTLEN, (dp.y << 16) | height);
447         mgawrite32(mga, DWGCTL + GO, DWG_BITBLT | DWG_SHIFTZERO | DWG_BFCOL | DWG_REPLACE);
448
449         while(mgaread32(mga, STATUS) & 0x00010000)
450                 ;
451
452         return 1;
453 }
454
455 static void
456 mga4xxdrawinit(VGAscr *scr)
457 {
458         uchar *mga;
459
460         if(scr->mmio == 0)
461                 return;
462
463         mga = (uchar*)scr->mmio;
464
465         mgawrite32(mga, SRCORG, 0);
466         mgawrite32(mga, DSTORG, 0);
467         mgawrite32(mga, YDSTORG, 0);
468         mgawrite32(mga, ZORG, 0);
469         mgawrite32(mga, PLNWRT, ~0);
470         mgawrite32(mga, FCOL, 0xffff0000);
471         mgawrite32(mga, CXBNDRY, 0xFFFF0000);
472         mgawrite32(mga, YTOP, 0);
473         mgawrite32(mga, YBOT, 0x01FFFFFF);
474         mgawrite32(mga, PITCH, Dx(scr->gscreen->r) & ((1 << 13) - 1));
475         switch(scr->gscreen->depth){
476         case 8:
477                 mgawrite32(mga, MACCESS, 0);
478                 break;
479         case 16:
480                 mgawrite32(mga, MACCESS, 1);
481                 break;
482         case 24:
483                 mgawrite32(mga, MACCESS, 3);
484                 break;
485         case 32:
486                 mgawrite32(mga, MACCESS, 2);
487                 break;
488         default:
489                 return;         /* depth not supported ! */
490         }
491         scr->fill = mga4xxfill;
492         scr->scroll = mga4xxscroll;
493         scr->blank = mga4xxblank;
494 }
495
496 VGAdev vgamga4xxdev = {
497         "mga4xx",
498         mga4xxenable,           /* enable */
499         0,                                      /* disable */
500         0,                                      /* page */
501         0,                                      /* linear */
502         mga4xxdrawinit,
503 };
504
505 VGAcur vgamga4xxcur = {
506         "mga4xxhwgc",
507         dac4xxenable,
508         dac4xxdisable,
509         dac4xxload,
510         dac4xxmove,
511 };