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