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