]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vganeomagic.c
audiohda: reset irbsts bits in hdainterrupt() (thanks LordCreepity)
[plan9front.git] / sys / src / 9 / pc / vganeomagic.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/pci.h"
8 #include "../port/error.h"
9
10 #define Image   IMAGE
11 #include <draw.h>
12 #include <memdraw.h>
13 #include <cursor.h>
14 #include "screen.h"
15
16 typedef struct CursorNM CursorNM;
17 struct CursorNM {
18         int     enable;
19         int     x;
20         int     y;
21         int     colour1;
22         int     colour2;
23         int     addr;
24 };
25
26 static void
27 neomagicenable(VGAscr* scr)
28 {
29         Pcidev *p;
30         int bar, curoff, vmsize;
31         uvlong ioaddr;
32         ulong iosize;
33
34         /*
35          * scr->mmio holds the virtual address of the cursor registers
36          * in the MMIO space. This may need to change for older chips
37          * which have the MMIO space offset in the framebuffer region.
38          *
39          * scr->io holds the offset into mmio of the CursorNM struct.
40          */
41         if(scr->mmio)
42                 return;
43         p = scr->pci;
44         if(p == nil || p->vid != 0x10C8)
45                 return;
46         bar = 1;
47         switch(p->did){
48         case 0x0003:            /* MagicGraph 128ZV */
49                 bar = 0;
50                 if(p->mem[bar].bar & 1)
51                         return;
52                 ioaddr = (p->mem[bar].bar & ~0x0F) + 0x200000;
53                 iosize = 0x200000;
54                 curoff = 0x100;
55                 vmsize = 1152*1024;
56                 goto Map;
57         case 0x0083:            /* MagicGraph 128ZV+ */
58                 curoff = 0x100;
59                 vmsize = 1152*1024;
60                 break;
61         case 0x0004:            /* MagicGraph 128XD */
62                 curoff = 0x100;
63                 vmsize = 2048*1024;
64                 break;
65         case 0x0005:            /* MagicMedia 256AV */
66                 curoff = 0x1000;
67                 vmsize = 2560*1024;
68                 break;
69         case 0x0006:            /* MagicMedia 256ZX */
70                 curoff = 0x1000;
71                 vmsize = 4096*1024;
72                 break;
73         case 0x0016:            /* MagicMedia 256XL+ */
74                 curoff = 0x1000;
75                 /* Vaio VESA BIOS says 6080, but then hwgc doesn't work */
76                 vmsize = 4096*1024;
77                 break;
78         default:
79                 return;
80         }
81         if(p->mem[bar].bar & 1)
82                 return;
83         ioaddr = p->mem[bar].bar & ~0x0F;
84         iosize = p->mem[bar].size;
85 Map:
86         scr->mmio = vmap(ioaddr, iosize);
87         if(scr->mmio == nil)
88                 return;
89         addvgaseg("neomagicmmio", ioaddr, iosize);
90
91         /*
92          * Find a place for the cursor data in display memory.
93          * 2 cursor images might be needed, 1KB each so use the
94          * last 2KB of the framebuffer.
95          */
96         scr->storage = vmsize-2*1024;
97         scr->io = curoff;
98         vgalinearpci(scr);
99         if(scr->paddr)
100                 addvgaseg("neomagicscreen", scr->paddr, scr->apsize);
101 }
102
103 static void
104 neomagiccurdisable(VGAscr* scr)
105 {
106         CursorNM *cursornm;
107
108         if(scr->mmio == 0)
109                 return;
110         cursornm = (void*)((char*)scr->mmio + scr->io);
111         cursornm->enable = 0;
112 }
113
114 static void
115 neomagicinitcursor(VGAscr* scr, int xo, int yo, int index)
116 {
117         uchar *p;
118         uint p0, p1;
119         int x, y;
120
121         p = (uchar*)scr->vaddr;
122         p += scr->storage + index*1024;
123
124         for(y = yo; y < 16; y++){
125                 p0 = scr->set[2*y];
126                 p1 = scr->set[2*y+1];
127                 if(xo){
128                         p0 = (p0<<xo)|(p1>>(8-xo));
129                         p1 <<= xo;
130                 }
131                 *p++ = p0;
132                 *p++ = p1;
133
134                 for(x = 16; x < 64; x += 8)
135                         *p++ = 0x00;
136
137                 p0 = scr->clr[2*y]|scr->set[2*y];
138                 p1 = scr->clr[2*y+1]|scr->set[2*y+1];
139                 if(xo){
140                         p0 = (p0<<xo)|(p1>>(8-xo));
141                         p1 <<= xo;
142                 }
143                 *p++ = p0;
144                 *p++ = p1;
145
146                 for(x = 16; x < 64; x += 8)
147                         *p++ = 0x00;
148         }
149         while(y < 64+yo){
150                 for(x = 0; x < 64; x += 8){
151                         *p++ = 0x00;
152                         *p++ = 0x00;
153                 }
154                 y++;
155         }
156 }
157
158 static void
159 neomagiccurload(VGAscr* scr, Cursor* curs)
160 {
161         CursorNM *cursornm;
162
163         if(scr->mmio == 0)
164                 return;
165         cursornm = (void*)((char*)scr->mmio + scr->io);
166
167         cursornm->enable = 0;
168         memmove(&scr->Cursor, curs, sizeof(Cursor));
169         neomagicinitcursor(scr, 0, 0, 0);
170         cursornm->enable = 1;
171 }
172
173 static int
174 neomagiccurmove(VGAscr* scr, Point p)
175 {
176         CursorNM *cursornm;
177         int addr, index, x, xo, y, yo;
178
179         if(scr->mmio == 0)
180                 return 1;
181         cursornm = (void*)((char*)scr->mmio + scr->io);
182
183         index = 0;
184         if((x = p.x+scr->offset.x) < 0){
185                 xo = -x;
186                 x = 0;
187         }
188         else
189                 xo = 0;
190         if((y = p.y+scr->offset.y) < 0){
191                 yo = -y;
192                 y = 0;
193         }
194         else
195                 yo = 0;
196
197         if(xo || yo){
198                 index = 1;
199                 neomagicinitcursor(scr, xo, yo, index);
200         }
201         addr = ((scr->storage+(1024*index))>>10) & 0xFFF;
202         addr = ((addr & 0x00F)<<8)|((addr>>4) & 0xFF);
203         if(cursornm->addr != addr)
204                 cursornm->addr = addr;
205
206         cursornm->x = x;
207         cursornm->y = y;
208
209         return 0;
210 }
211
212 static void
213 neomagiccurenable(VGAscr* scr)
214 {
215         CursorNM *cursornm;
216
217         neomagicenable(scr);
218         if(scr->mmio == 0)
219                 return;
220         cursornm = (void*)((char*)scr->mmio + scr->io);
221         cursornm->enable = 0;
222
223         /*
224          * Cursor colours.
225          */
226         cursornm->colour1 = (Pblack<<16)|(Pblack<<8)|Pblack;
227         cursornm->colour2 = (Pwhite<<16)|(Pwhite<<8)|Pwhite;
228
229         /*
230          * Load, locate and enable the 64x64 cursor.
231          */
232         neomagiccurload(scr, &cursor);
233         neomagiccurmove(scr, ZP);
234         cursornm->enable = 1;
235 }
236
237 static int neomagicbltflags;
238
239 /* registers */
240 enum {
241         BltStat = 0,
242         BltCntl = 1,
243         XPColor = 2,
244         FGColor = 3,
245         BGColor = 4,
246         Pitch = 5,
247         ClipLT = 6,
248         ClipRB = 7,
249         SrcBitOff = 8,
250         SrcStartOff = 9,
251
252         DstStartOff = 11,
253         XYExt = 12,
254
255         PageCntl = 20,
256         PageBase,
257         PostBase,
258         PostPtr,
259         DataPtr,
260 };
261
262 /* flags */
263 enum {
264         NEO_BS0_BLT_BUSY =      0x00000001,
265         NEO_BS0_FIFO_AVAIL =    0x00000002,
266         NEO_BS0_FIFO_PEND =     0x00000004,
267
268         NEO_BC0_DST_Y_DEC =     0x00000001,
269         NEO_BC0_X_DEC =         0x00000002,
270         NEO_BC0_SRC_TRANS =     0x00000004,
271         NEO_BC0_SRC_IS_FG =     0x00000008,
272         NEO_BC0_SRC_Y_DEC =     0x00000010,
273         NEO_BC0_FILL_PAT =      0x00000020,
274         NEO_BC0_SRC_MONO =      0x00000040,
275         NEO_BC0_SYS_TO_VID =    0x00000080,
276
277         NEO_BC1_DEPTH8 =        0x00000100,
278         NEO_BC1_DEPTH16 =       0x00000200,
279         NEO_BC1_DEPTH24 =       0x00000300,
280         NEO_BC1_X_320 =         0x00000400,
281         NEO_BC1_X_640 =         0x00000800,
282         NEO_BC1_X_800 =         0x00000c00,
283         NEO_BC1_X_1024 =        0x00001000,
284         NEO_BC1_X_1152 =        0x00001400,
285         NEO_BC1_X_1280 =        0x00001800,
286         NEO_BC1_X_1600 =        0x00001c00,
287         NEO_BC1_DST_TRANS =     0x00002000,
288         NEO_BC1_MSTR_BLT =      0x00004000,
289         NEO_BC1_FILTER_Z =      0x00008000,
290
291         NEO_BC2_WR_TR_DST =     0x00800000,
292
293         NEO_BC3_SRC_XY_ADDR =   0x01000000,
294         NEO_BC3_DST_XY_ADDR =   0x02000000,
295         NEO_BC3_CLIP_ON =       0x04000000,
296         NEO_BC3_FIFO_EN =       0x08000000,
297         NEO_BC3_BLT_ON_ADDR =   0x10000000,
298         NEO_BC3_SKIP_MAPPING =  0x80000000,
299
300         NEO_MODE1_DEPTH8 =      0x0100,
301         NEO_MODE1_DEPTH16 =     0x0200,
302         NEO_MODE1_DEPTH24 =     0x0300,
303         NEO_MODE1_X_320 =       0x0400,
304         NEO_MODE1_X_640 =       0x0800,
305         NEO_MODE1_X_800 =       0x0c00,
306         NEO_MODE1_X_1024 =      0x1000,
307         NEO_MODE1_X_1152 =      0x1400,
308         NEO_MODE1_X_1280 =      0x1800,
309         NEO_MODE1_X_1600 =      0x1c00,
310         NEO_MODE1_BLT_ON_ADDR = 0x2000,
311 };
312
313 /* Raster Operations */
314 enum {
315         GXclear =               0x000000,       /* 0x0000 */
316         GXand =                 0x080000,       /* 0x1000 */
317         GXandReverse =          0x040000,       /* 0x0100 */
318         GXcopy =                0x0c0000,       /* 0x1100 */
319         GXandInvert =           0x020000,       /* 0x0010 */
320         GXnoop =                0x0a0000,       /* 0x1010 */
321         GXxor =                 0x060000,       /* 0x0110 */
322         GXor =                  0x0e0000,       /* 0x1110 */
323         GXnor =                 0x010000,       /* 0x0001 */
324         GXequiv =               0x090000,       /* 0x1001 */
325         GXinvert =              0x050000,       /* 0x0101 */
326         GXorReverse =           0x0d0000,       /* 0x1101 */
327         GXcopyInvert =          0x030000,       /* 0x0011 */
328         GXorInverted =          0x0b0000,       /* 0x1011 */
329         GXnand =                0x070000,       /* 0x0111 */
330         GXset =                 0x0f0000,       /* 0x1111 */
331 };
332
333 static void
334 waitforidle(VGAscr *scr)
335 {
336         ulong *mmio;
337         long x;
338
339         mmio = scr->mmio;
340         x = 0;
341         while((mmio[BltStat] & NEO_BS0_BLT_BUSY) && x++ < 1000000)
342                 ;
343         //if(x >= 1000000)
344         //      iprint("idle stat %lud scrmmio %#.8lux scr %#p pc %#p\n", mmio[BltStat], scr->mmio, scr, getcallerpc(&scr));
345 }
346
347 static void
348 waitforfifo(VGAscr *scr, int entries)
349 {
350         ulong *mmio;
351         long x;
352
353         mmio = scr->mmio;
354         x = 0;
355         while(((mmio[BltStat]>>8) < entries) && x++ < 1000000)
356                 ;
357         //if(x >= 1000000)
358         //      iprint("fifo stat %d scrmmio %#.8lux scr %#p pc %#p\n", mmio[BltStat]>>8, scr->mmio, scr, getcallerpc(&scr));
359         /* DirectFB says the above doesn't work.  if so... */
360         /* waitforidle(scr); */
361 }
362
363 static int
364 neomagichwfill(VGAscr *scr, Rectangle r, ulong sval)
365 {
366         ulong *mmio;
367
368         mmio = scr->mmio;
369
370         waitforfifo(scr, 1);
371         mmio[FGColor] = sval;
372         waitforfifo(scr, 3);
373         mmio[BltCntl] = neomagicbltflags
374                 | NEO_BC3_FIFO_EN
375                 | NEO_BC0_SRC_IS_FG
376                 | NEO_BC3_SKIP_MAPPING
377                 | GXcopy;
378         mmio[DstStartOff] = scr->paddr
379                 + r.min.y*scr->gscreen->width*sizeof(ulong)
380                 + r.min.x*scr->gscreen->depth/BI2BY;
381         mmio[XYExt] = (Dy(r) << 16) | (Dx(r) & 0xffff);
382         waitforidle(scr);
383         return 1;
384 }
385
386 static int
387 neomagichwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
388 {
389         ulong *mmio;
390         int pitch, pixel;
391
392         mmio = scr->mmio;
393
394         pitch = scr->gscreen->width*sizeof(ulong);
395         pixel = scr->gscreen->depth/BI2BY;
396
397         waitforfifo(scr, 4);
398         if (r.min.y < sr.min.y || (r.min.y == sr.min.y && r.min.x < sr.min.x)) {
399                 /* start from upper-left */
400                 mmio[BltCntl] = neomagicbltflags
401                         | NEO_BC3_FIFO_EN
402                         | NEO_BC3_SKIP_MAPPING
403                         | GXcopy;
404                 mmio[SrcStartOff] = scr->paddr
405                         + sr.min.y*pitch + sr.min.x*pixel;
406                 mmio[DstStartOff] = scr->paddr
407                         + r.min.y*pitch + r.min.x*pixel;
408         } else {
409                 /* start from lower-right */
410                 mmio[BltCntl] = neomagicbltflags
411                         | NEO_BC0_X_DEC
412                         | NEO_BC0_DST_Y_DEC
413                         | NEO_BC0_SRC_Y_DEC
414                         | NEO_BC3_FIFO_EN
415                         | NEO_BC3_SKIP_MAPPING
416                         | GXcopy;
417                 mmio[SrcStartOff] = scr->paddr
418                         + (sr.max.y-1)*pitch + (sr.max.x-1)*pixel;
419                 mmio[DstStartOff] = scr->paddr
420                         + (r.max.y-1)*pitch + (r.max.x-1)*pixel;
421         }
422         mmio[XYExt] = (Dy(r) << 16) | (Dx(r) & 0xffff);
423         waitforidle(scr);
424         return 1;
425 }
426
427 static void
428 neomagicdrawinit(VGAscr *scr)
429 {
430         ulong *mmio;
431         uint bltmode, pitch;
432
433         mmio = scr->mmio;
434
435         pitch = scr->gscreen->width*sizeof(ulong);
436
437         neomagicbltflags = bltmode = 0;
438
439         switch(scr->gscreen->depth) {
440         case 8:
441                 bltmode |= NEO_MODE1_DEPTH8;
442                 neomagicbltflags |= NEO_BC1_DEPTH8;
443                 break;
444         case 16:
445                 bltmode |= NEO_MODE1_DEPTH16;
446                 neomagicbltflags |= NEO_BC1_DEPTH16;
447                 break;
448         case 24:        /* I can't get it to work, and XFree86 doesn't either. */
449         default:        /* give up */
450                 return;
451         }
452
453         switch(Dx(scr->gscreen->r)) {
454         case 320:
455                 bltmode |= NEO_MODE1_X_320;
456                 neomagicbltflags |= NEO_BC1_X_320;
457                 break;
458         case 640:
459                 bltmode |= NEO_MODE1_X_640;
460                 neomagicbltflags |= NEO_BC1_X_640;
461                 break;
462         case 800:
463                 bltmode |= NEO_MODE1_X_800;
464                 neomagicbltflags |= NEO_BC1_X_800;
465                 break;
466         case 1024:
467                 bltmode |= NEO_MODE1_X_1024;
468                 neomagicbltflags |= NEO_BC1_X_1024;
469                 break;
470         case 1152:
471                 bltmode |= NEO_MODE1_X_1152;
472                 neomagicbltflags |= NEO_BC1_X_1152;
473                 break;
474         case 1280:
475                 bltmode |= NEO_MODE1_X_1280;
476                 neomagicbltflags |= NEO_BC1_X_1280;
477                 break;
478         case 1600:
479                 bltmode |= NEO_MODE1_X_1600;
480                 neomagicbltflags |= NEO_BC1_X_1600;
481                 break;
482         default:
483                 /* don't worry about it */
484                 break;
485         }
486
487         waitforidle(scr);
488         mmio[BltStat] = bltmode << 16;
489         mmio[Pitch] = (pitch << 16) | (pitch & 0xffff);
490
491         scr->fill = neomagichwfill;
492         scr->scroll = neomagichwscroll;
493 }
494
495 VGAdev vganeomagicdev = {
496         "neomagic",
497
498         neomagicenable,
499         nil,
500         nil,
501         nil,
502         neomagicdrawinit,
503 };
504
505 VGAcur vganeomagiccur = {
506         "neomagichwgc",
507
508         neomagiccurenable,
509         neomagiccurdisable,
510         neomagiccurload,
511         neomagiccurmove,
512 };
513