FreeBSD/Linux Kernel Cross Reference
sys/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
Cache object: 688fb460d34dd160022c892185d3c38f
|