]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vganvidia.c
audiohda: first attempt on audio recording support for intel hda audio, distinguish...
[plan9front.git] / sys / src / 9 / pc / vganvidia.c
1
2 /* Portions of this file derived from work with the following copyright */
3
4  /***************************************************************************\
5 |*                                                                           *|
6 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
7 |*                                                                           *|
8 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
9 |*     international laws.  Users and possessors of this source code are     *|
10 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
11 |*     use this code in individual and commercial software.                  *|
12 |*                                                                           *|
13 |*     Any use of this source code must include,  in the user documenta-     *|
14 |*     tion and  internal comments to the code,  notices to the end user     *|
15 |*     as follows:                                                           *|
16 |*                                                                           *|
17 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
18 |*                                                                           *|
19 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
20 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
21 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
22 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
23 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
24 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
25 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
26 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
27 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
28 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
29 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
30 |*                                                                           *|
31 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
32 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
33 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
34 |*     computer  software  documentation,"  as such  terms  are  used in     *|
35 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
36 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
37 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
38 |*     all U.S. Government End Users  acquire the source code  with only     *|
39 |*     those rights set forth herein.                                        *|
40 |*                                                                           *|
41  \***************************************************************************/
42
43 #include "u.h"
44 #include "../port/lib.h"
45 #include "mem.h"
46 #include "dat.h"
47 #include "fns.h"
48 #include "io.h"
49 #include "../port/error.h"
50
51 #define Image   IMAGE
52 #include <draw.h>
53 #include <memdraw.h>
54 #include <cursor.h>
55 #include "screen.h"
56 #include "nv_dma.h"
57
58 enum {
59         Pramin = 0x00710000,
60         Pramdac = 0x00680000,
61         Fifo = 0x00800000,
62         Pgraph = 0x00400000,
63         Pfb = 0x00100000
64 };
65
66 enum {
67         hwCurPos = Pramdac + 0x0300,
68 };
69
70 #define SKIPS 8
71
72 static struct {
73         ulong   *dmabase;
74         int     dmacurrent;
75         int     dmaput;
76         int     dmafree;
77         int     dmamax;
78 } nv;
79
80 static void
81 nvidiaenable(VGAscr* scr)
82 {
83         Pcidev *p;
84         ulong *q;
85         int tmp;
86
87         if(scr->mmio)
88                 return;
89         p = scr->pci;
90         if(p == nil)
91                 return;
92         scr->id = p->did;
93
94         scr->mmio = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
95         if(scr->mmio == nil)
96                 return;
97         addvgaseg("nvidiammio", p->mem[0].bar&~0x0F, p->mem[0].size);
98         vgalinearpci(scr);
99         if(scr->apsize)
100                 addvgaseg("nvidiascreen", scr->paddr, scr->apsize);
101         /* find video memory size */
102         switch (scr->id & 0x0ff0) {
103         case 0x0020:
104         case 0x00A0:
105                 q = (void*)((uchar*)scr->mmio + Pfb);
106                 tmp = *q;
107                 if (tmp & 0x0100) {
108                         scr->storage = ((tmp >> 12) & 0x0F) * 1024 + 1024 * 2;
109                 } else {
110                         tmp &= 0x03;
111                         if (tmp)
112                                 scr->storage = (1024*1024*2) << tmp;
113                         else
114                                 scr->storage = 1024*1024*32;
115                 }
116                 break;
117         case 0x01A0:
118                 p = pcimatchtbdf(MKBUS(BusPCI, 0, 0, 1));
119                 tmp = pcicfgr32(p, 0x7C);
120                 scr->storage = (((tmp >> 6) & 31) + 1) * 1024 * 1024;
121                 break;
122         case 0x01F0:
123                 p = pcimatchtbdf(MKBUS(BusPCI, 0, 0, 1));
124                 tmp = pcicfgr32(p, 0x84);
125                 scr->storage = (((tmp >> 4) & 127) + 1) * 1024 * 1024;
126                 break;
127         default:
128                 q = (void*)((uchar*)scr->mmio + Pfb + 0x020C);
129                 tmp = (*q >> 20) & 0xFFF;
130                 if (tmp == 0)
131                         tmp = 16;
132                 scr->storage = tmp*1024*1024;
133                 break;
134         }
135 }
136
137 static void
138 nvidialinear(VGAscr *, int, int)
139 {
140 }
141
142 static void
143 nvidiacurdisable(VGAscr* scr)
144 {
145         if(scr->mmio == 0)
146                 return;
147
148         vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01);
149 }
150
151
152 static void
153 nvidiacurload(VGAscr* scr, Cursor* curs)
154 {
155         ulong*  p;
156         int     i,j;
157         ushort  c,s;
158         ulong   tmp;
159
160         if(scr->mmio == 0)
161                 return;
162
163         vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01);
164
165         switch (scr->id & 0x0ff0) {
166         case 0x0020:
167         case 0x00A0:
168                 p = (void*)((uchar*)scr->mmio + Pramin + 0x1E00 * 4);
169                 break;
170         default:
171                 /*
172                  * Reset the cursor location, since the kernel may
173                  * have allocated less storage than aux/vga
174                  * expected.
175                  */
176                 tmp = scr->apsize - 96*1024;
177                 p = (void*)((uchar*)scr->vaddr + tmp);
178                 vgaxo(Crtx, 0x30, 0x80|(tmp>>17));
179                 vgaxo(Crtx, 0x31, (tmp>>11)<<2);
180                 vgaxo(Crtx, 0x2F, tmp>>24);
181                 break;
182         }
183
184         for(i=0; i<16; i++) {
185                 c = (curs->clr[2 * i] << 8) | curs->clr[2 * i+1];
186                 s = (curs->set[2 * i] << 8) | curs->set[2 * i+1];
187                 tmp = 0;
188                 for (j=0; j<16; j++){
189                         if(s&0x8000)
190                                 tmp |= 0x80000000;
191                         else if(c&0x8000)
192                                 tmp |= 0xFFFF0000;
193                         if (j&0x1){
194                                 *p++ = tmp;
195                                 tmp = 0;
196                         } else {
197                                 tmp>>=16;
198                         }
199                         c<<=1;
200                         s<<=1;
201                 }
202                 for (j=0; j<8; j++)
203                         *p++ = 0;
204         }
205         for (i=0; i<256; i++)
206                 *p++ = 0;
207
208         scr->offset = curs->offset;
209         vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01);
210 }
211
212 static int
213 nvidiacurmove(VGAscr* scr, Point p)
214 {
215         ulong*  cursorpos;
216
217         if(scr->mmio == 0)
218                 return 1;
219
220         cursorpos = (void*)((uchar*)scr->mmio + hwCurPos);
221         *cursorpos = ((p.y+scr->offset.y)<<16)|((p.x+scr->offset.x) & 0xFFFF);
222
223         return 0;
224 }
225
226 static void
227 nvidiacurenable(VGAscr* scr)
228 {
229         nvidiaenable(scr);
230         if(scr->mmio == 0)
231                 return;
232
233         vgaxo(Crtx, 0x1F, 0x57);
234
235         nvidiacurload(scr, &arrow);
236         nvidiacurmove(scr, ZP);
237
238         vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01);
239 }
240
241 void
242 writeput(VGAscr *scr, int data)
243 {
244         uchar   *p, scratch;
245         ulong   *fifo;
246
247         outb(0x3D0,0);
248         p = scr->vaddr;
249         scratch = *p;
250         fifo = (void*)((uchar*)scr->mmio + Fifo);
251         fifo[0x10] = (data << 2);
252         USED(scratch);
253 }
254
255 ulong
256 readget(VGAscr *scr)
257 {
258         ulong   *fifo;
259
260         fifo = (void*)((uchar*)scr->mmio + Fifo);
261         return (fifo[0x0011] >> 2);
262 }
263
264 void
265 nvdmakickoff(VGAscr *scr)
266 {
267         if(nv.dmacurrent != nv.dmaput) {
268                 nv.dmaput = nv.dmacurrent;
269                 writeput(scr, nv.dmaput);
270         }
271 }
272
273 static void
274 nvdmanext(ulong data)
275 {
276         nv.dmabase[nv.dmacurrent++] = data;
277 }
278
279 void
280 nvdmawait(VGAscr *scr, int size)
281 {
282         int dmaget;
283
284         size++;
285
286         while(nv.dmafree < size) {
287                 dmaget = readget(scr);
288
289                 if(nv.dmaput >= dmaget) {
290                         nv.dmafree = nv.dmamax - nv.dmacurrent;
291                         if(nv.dmafree < size) {
292                                 nvdmanext(0x20000000);
293                                 if(dmaget <= SKIPS) {
294                                         if (nv.dmaput <= SKIPS) /* corner case - will be idle */
295                                                 writeput(scr, SKIPS + 1);
296                                         do { dmaget = readget(scr); }
297                                         while(dmaget <= SKIPS);
298                                 }
299                                 writeput(scr, SKIPS);
300                                 nv.dmacurrent = nv.dmaput = SKIPS;
301                                 nv.dmafree = dmaget - (SKIPS + 1);
302                         }
303                 } else
304                         nv.dmafree = dmaget - nv.dmacurrent - 1;
305         }
306 }
307
308
309 static void
310 nvdmastart(VGAscr *scr, ulong tag, int size)
311 {
312         if (nv.dmafree <= size)
313                 nvdmawait(scr, size);
314         nvdmanext((size << 18) | tag);
315         nv.dmafree -= (size + 1);
316 }
317
318 static void
319 waitforidle(VGAscr *scr)
320 {
321         ulong*  pgraph;
322         int x;
323
324         pgraph = (void*)((uchar*)scr->mmio + Pgraph);
325
326         x = 0;
327         while((readget(scr) != nv.dmaput) && x++ < 1000000)
328                 ;
329         if(x >= 1000000)
330                 iprint("idle stat %lud put %d scr %#p pc %#p\n", readget(scr), nv.dmaput, scr, getcallerpc(&scr));
331
332         x = 0;
333         while(pgraph[0x00000700/4] & 0x01 && x++ < 1000000)
334                 ;
335
336         if(x >= 1000000)
337                 iprint("idle stat %lud scrio %#p scr %#p pc %#p\n", *pgraph, scr->mmio, scr, getcallerpc(&scr));
338 }
339
340 static int
341 nvresetgraphics(VGAscr *scr)
342 {
343         ulong   surfaceFormat, patternFormat, rectFormat, lineFormat;
344         int     pitch, i;
345
346         if(scr->paddr == 0)
347                 return -1;
348
349         pitch = scr->gscreen->width*BY2WD;
350
351         /*
352          * DMA is at the end of the virtual window,
353          * but we might have cut it short when mapping it.
354          */
355         if(nv.dmabase == nil){
356                 if(scr->storage <= scr->apsize)
357                         nv.dmabase = (ulong*)((uchar*)scr->vaddr + scr->storage - 128*1024);
358                 else{
359                         nv.dmabase = (void*)vmap(scr->paddr + scr->storage - 128*1024, 128*1024);
360                         if(nv.dmabase == 0){
361                                 print("vmap nvidia dma failed\n");
362                                 return -1;
363                         }
364                 }
365         }
366
367         for(i=0; i<SKIPS; i++)
368                 nv.dmabase[i] = 0x00000000;
369
370         nv.dmabase[0x0 + SKIPS] = 0x00040000;
371         nv.dmabase[0x1 + SKIPS] = 0x80000010;
372         nv.dmabase[0x2 + SKIPS] = 0x00042000;
373         nv.dmabase[0x3 + SKIPS] = 0x80000011;
374         nv.dmabase[0x4 + SKIPS] = 0x00044000;
375         nv.dmabase[0x5 + SKIPS] = 0x80000012;
376         nv.dmabase[0x6 + SKIPS] = 0x00046000;
377         nv.dmabase[0x7 + SKIPS] = 0x80000013;
378         nv.dmabase[0x8 + SKIPS] = 0x00048000;
379         nv.dmabase[0x9 + SKIPS] = 0x80000014;
380         nv.dmabase[0xA + SKIPS] = 0x0004A000;
381         nv.dmabase[0xB + SKIPS] = 0x80000015;
382         nv.dmabase[0xC + SKIPS] = 0x0004C000;
383         nv.dmabase[0xD + SKIPS] = 0x80000016;
384         nv.dmabase[0xE + SKIPS] = 0x0004E000;
385         nv.dmabase[0xF + SKIPS] = 0x80000017;
386
387         nv.dmaput = 0;
388         nv.dmacurrent = 16 + SKIPS;
389         nv.dmamax = 8191;
390         nv.dmafree = nv.dmamax - nv.dmacurrent;
391
392         switch(scr->gscreen->depth) {
393         case 32:
394         case 24:
395                 surfaceFormat = SURFACE_FORMAT_DEPTH24;
396                 patternFormat = PATTERN_FORMAT_DEPTH24;
397                 rectFormat = RECT_FORMAT_DEPTH24;
398                 lineFormat = LINE_FORMAT_DEPTH24;
399                 break;
400         case 16:
401         case 15:
402                 surfaceFormat = SURFACE_FORMAT_DEPTH16;
403                 patternFormat = PATTERN_FORMAT_DEPTH16;
404                 rectFormat = RECT_FORMAT_DEPTH16;
405                 lineFormat = LINE_FORMAT_DEPTH16;
406                 break;
407         default:
408                 surfaceFormat = SURFACE_FORMAT_DEPTH8;
409                 patternFormat = PATTERN_FORMAT_DEPTH8;
410                 rectFormat = RECT_FORMAT_DEPTH8;
411                 lineFormat = LINE_FORMAT_DEPTH8;
412                 break;
413         }
414
415         nvdmastart(scr, SURFACE_FORMAT, 4);
416         nvdmanext(surfaceFormat);
417         nvdmanext(pitch | (pitch << 16));
418         nvdmanext(0);
419         nvdmanext(0);
420
421         nvdmastart(scr, PATTERN_FORMAT, 1);
422         nvdmanext(patternFormat);
423
424         nvdmastart(scr, RECT_FORMAT, 1);
425         nvdmanext(rectFormat);
426
427         nvdmastart(scr, LINE_FORMAT, 1);
428         nvdmanext(lineFormat);
429
430         nvdmastart(scr, PATTERN_COLOR_0, 4);
431         nvdmanext(~0);
432         nvdmanext(~0);
433         nvdmanext(~0);
434         nvdmanext(~0);
435
436         nvdmastart(scr, ROP_SET, 1);
437         nvdmanext(0xCC);
438
439         nvdmakickoff(scr);
440         waitforidle(scr);
441
442         return 0;
443 }
444
445
446 static int
447 nvidiahwfill(VGAscr *scr, Rectangle r, ulong sval)
448 {
449         nvdmastart(scr, RECT_SOLID_COLOR, 1);
450         nvdmanext(sval);
451
452         nvdmastart(scr, RECT_SOLID_RECTS(0), 2);
453         nvdmanext((r.min.x << 16) | r.min.y);
454         nvdmanext((Dx(r) << 16) | Dy(r));
455
456         //if ( (Dy(r) * Dx(r)) >= 512)
457                 nvdmakickoff(scr);
458
459         waitforidle(scr);
460
461         return 1;
462 }
463
464 static int
465 nvidiahwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
466 {
467         nvdmastart(scr, BLIT_POINT_SRC, 3);
468         nvdmanext((sr.min.y << 16) | sr.min.x);
469         nvdmanext((r.min.y << 16) | r.min.x);
470         nvdmanext((Dy(r) << 16) | Dx(r));
471
472         //if ( (Dy(r) * Dx(r)) >= 512)
473                 nvdmakickoff(scr);
474
475         waitforidle(scr);
476
477         return 1;
478 }
479
480 void
481 nvidiablank(VGAscr*, int blank)
482 {
483         uchar seq1, crtc1A;
484
485         seq1 = vgaxi(Seqx, 1) & ~0x20;
486         crtc1A = vgaxi(Crtx, 0x1A) & ~0xC0;
487
488         if(blank){
489                 seq1 |= 0x20;
490 //              crtc1A |= 0xC0;
491                 crtc1A |= 0x80;
492         }
493
494         vgaxo(Seqx, 1, seq1);
495         vgaxo(Crtx, 0x1A, crtc1A);
496 }
497
498 static void
499 nvidiadrawinit(VGAscr *scr)
500 {
501         scr->blank = nvidiablank;
502         if(nvresetgraphics(scr) < 0)
503                 return;
504         scr->fill = nvidiahwfill;
505         scr->scroll = nvidiahwscroll;
506 }
507
508 VGAdev vganvidiadev = {
509         "nvidia",
510
511         nvidiaenable,
512         nil,
513         nil,
514         nvidialinear,
515         nvidiadrawinit,
516 };
517
518 VGAcur vganvidiacur = {
519         "nvidiahwgc",
520
521         nvidiacurenable,
522         nvidiacurdisable,
523         nvidiacurload,
524         nvidiacurmove,
525 };