xref: /plan9/sys/src/9/pc/vganvidia.c (revision cb8c047aa49e908a428eac8b13623e1b242fa11e)
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 struct {
73 	ulong	*dmabase;
74 	int		dmacurrent;
75 	int		dmaput;
76 	int		dmafree;
77 	int		dmamax;
78 } nv;
79 
80 static Pcidev*
nvidiapci(void)81 nvidiapci(void)
82 {
83 	Pcidev *p;
84 
85 	p = nil;
86 	while((p = pcimatch(p, 0x10DE, 0)) != nil){
87 		if(p->did >= 0x20 && p->ccrb == 3)	/* video card */
88 			return p;
89 	}
90 	return nil;
91 }
92 
93 static void
nvidialinear(VGAscr *,int,int)94 nvidialinear(VGAscr*, int, int)
95 {
96 }
97 
98 static void
nvidiaenable(VGAscr * scr)99 nvidiaenable(VGAscr* scr)
100 {
101 	Pcidev *p;
102 	ulong *q;
103 	int tmp;
104 
105 	if(scr->mmio)
106 		return;
107 	p = nvidiapci();
108 	if(p == nil)
109 		return;
110 	scr->id = p->did;
111 	scr->pci = p;
112 
113 	scr->mmio = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
114 	if(scr->mmio == nil)
115 		return;
116 	addvgaseg("nvidiammio", p->mem[0].bar&~0x0F, p->mem[0].size);
117 
118 	vgalinearpci(scr);
119 	if(scr->apsize)
120 		addvgaseg("nvidiascreen", scr->paddr, scr->apsize);
121 
122 	/* find video memory size */
123 	switch (scr->id & 0x0ff0) {
124 	case 0x0020:
125 	case 0x00A0:
126 		q = (void*)((uchar*)scr->mmio + Pfb);
127 		tmp = *q;
128 		if (tmp & 0x0100) {
129 			scr->storage = ((tmp >> 12) & 0x0F) * 1024 + 1024 * 2;
130 		} else {
131 			tmp &= 0x03;
132 			if (tmp)
133 				scr->storage = (1024*1024*2) << tmp;
134 			else
135 				scr->storage = 1024*1024*32;
136 		}
137 		break;
138 	case 0x01A0:
139 		p = pcimatchtbdf(MKBUS(BusPCI, 0, 0, 1));
140 		tmp = pcicfgr32(p, 0x7C);
141 		scr->storage = (((tmp >> 6) & 31) + 1) * 1024 * 1024;
142 		break;
143 	case 0x01F0:
144 		p = pcimatchtbdf(MKBUS(BusPCI, 0, 0, 1));
145 		tmp = pcicfgr32(p, 0x84);
146 		scr->storage = (((tmp >> 4) & 127) + 1) * 1024 * 1024;
147 		break;
148 	default:
149 		q = (void*)((uchar*)scr->mmio + Pfb + 0x020C);
150 		tmp = (*q >> 20) & 0xFFF;
151 		if (tmp == 0)
152 			tmp = 16;
153 		scr->storage = tmp*1024*1024;
154 		break;
155 	}
156 }
157 
158 static void
nvidiacurdisable(VGAscr * scr)159 nvidiacurdisable(VGAscr* scr)
160 {
161 	if(scr->mmio == 0)
162 		return;
163 
164 	vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01);
165 }
166 
167 
168 static void
nvidiacurload(VGAscr * scr,Cursor * curs)169 nvidiacurload(VGAscr* scr, Cursor* curs)
170 {
171 	ulong*	p;
172 	int	i,j;
173 	ushort	c,s;
174 	ulong	tmp;
175 
176 	if(scr->mmio == 0)
177 		return;
178 
179 	vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) & ~0x01);
180 
181 	switch (scr->id & 0x0ff0) {
182 	case 0x0020:
183 	case 0x00A0:
184 		p = (void*)((uchar*)scr->mmio + Pramin + 0x1E00 * 4);
185 		break;
186 	default:
187 		/*
188 		 * Reset the cursor location, since the kernel may
189 		 * have allocated less storage than aux/vga
190 		 * expected.
191 		 */
192 		tmp = scr->apsize - 96*1024;
193 		p = (void*)((uchar*)scr->vaddr + tmp);
194 		vgaxo(Crtx, 0x30, 0x80|(tmp>>17));
195 		vgaxo(Crtx, 0x31, (tmp>>11)<<2);
196 		vgaxo(Crtx, 0x2F, tmp>>24);
197 		break;
198 	}
199 
200 	for(i=0; i<16; i++) {
201 		c = (curs->clr[2 * i] << 8) | curs->clr[2 * i+1];
202 		s = (curs->set[2 * i] << 8) | curs->set[2 * i+1];
203 		tmp = 0;
204 		for (j=0; j<16; j++){
205 			if(s&0x8000)
206 				tmp |= 0x80000000;
207 			else if(c&0x8000)
208 				tmp |= 0xFFFF0000;
209 			if (j&0x1){
210 				*p++ = tmp;
211 				tmp = 0;
212 			} else {
213 				tmp>>=16;
214 			}
215 			c<<=1;
216 			s<<=1;
217 		}
218 		for (j=0; j<8; j++)
219 			*p++ = 0;
220 	}
221 	for (i=0; i<256; i++)
222 		*p++ = 0;
223 
224 	scr->offset = curs->offset;
225 	vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01);
226 
227 	return;
228 }
229 
230 static int
nvidiacurmove(VGAscr * scr,Point p)231 nvidiacurmove(VGAscr* scr, Point p)
232 {
233 	ulong*	cursorpos;
234 
235 	if(scr->mmio == 0)
236 		return 1;
237 
238 	cursorpos = (void*)((uchar*)scr->mmio + hwCurPos);
239 	*cursorpos = ((p.y+scr->offset.y)<<16)|((p.x+scr->offset.x) & 0xFFFF);
240 
241 	return 0;
242 }
243 
244 static void
nvidiacurenable(VGAscr * scr)245 nvidiacurenable(VGAscr* scr)
246 {
247 	nvidiaenable(scr);
248 	if(scr->mmio == 0)
249 		return;
250 
251 	vgaxo(Crtx, 0x1F, 0x57);
252 
253 	nvidiacurload(scr, &arrow);
254 	nvidiacurmove(scr, ZP);
255 
256 	vgaxo(Crtx, 0x31, vgaxi(Crtx, 0x31) | 0x01);
257 }
258 
259 void
writeput(VGAscr * scr,int data)260 writeput(VGAscr *scr, int data)
261 {
262 	uchar	*p, scratch;
263 	ulong	*fifo;
264 
265 	outb(0x3D0,0);
266 	p = scr->vaddr;
267 	scratch = *p;
268 	fifo = (void*)((uchar*)scr->mmio + Fifo);
269 	fifo[0x10] = (data << 2);
270 	USED(scratch);
271 }
272 
273 ulong
readget(VGAscr * scr)274 readget(VGAscr *scr)
275 {
276 	ulong	*fifo;
277 
278 	fifo = (void*)((uchar*)scr->mmio + Fifo);
279 	return (fifo[0x0011] >> 2);
280 }
281 
282 void
nvdmakickoff(VGAscr * scr)283 nvdmakickoff(VGAscr *scr)
284 {
285 	if(nv.dmacurrent != nv.dmaput) {
286 		nv.dmaput = nv.dmacurrent;
287 		writeput(scr, nv.dmaput);
288 	}
289 }
290 
291 static void
nvdmanext(ulong data)292 nvdmanext(ulong data)
293 {
294 	nv.dmabase[nv.dmacurrent++] = data;
295 }
296 
297 void
nvdmawait(VGAscr * scr,int size)298 nvdmawait(VGAscr *scr, int size)
299 {
300 	int dmaget;
301 
302 	size++;
303 
304 	while(nv.dmafree < size) {
305 		dmaget = readget(scr);
306 
307 		if(nv.dmaput >= dmaget) {
308 			nv.dmafree = nv.dmamax - nv.dmacurrent;
309 			if(nv.dmafree < size) {
310 				nvdmanext(0x20000000);
311 				if(dmaget <= SKIPS) {
312 					if (nv.dmaput <= SKIPS) /* corner case - will be idle */
313 						writeput(scr, SKIPS + 1);
314 					do { dmaget = readget(scr); }
315 					while(dmaget <= SKIPS);
316 				}
317 				writeput(scr, SKIPS);
318 				nv.dmacurrent = nv.dmaput = SKIPS;
319 				nv.dmafree = dmaget - (SKIPS + 1);
320 			}
321 		} else
322 			nv.dmafree = dmaget - nv.dmacurrent - 1;
323 	}
324 }
325 
326 
327 static void
nvdmastart(VGAscr * scr,ulong tag,int size)328 nvdmastart(VGAscr *scr, ulong tag, int size)
329 {
330 	if (nv.dmafree <= size)
331 		nvdmawait(scr, size);
332 	nvdmanext((size << 18) | tag);
333 	nv.dmafree -= (size + 1);
334 }
335 
336 static void
waitforidle(VGAscr * scr)337 waitforidle(VGAscr *scr)
338 {
339 	ulong*	pgraph;
340 	int x;
341 
342 	pgraph = (void*)((uchar*)scr->mmio + Pgraph);
343 
344 	x = 0;
345 	while((readget(scr) != nv.dmaput) && x++ < 1000000)
346 		;
347 	if(x >= 1000000)
348 		iprint("idle stat %lud put %d scr %#p pc %#p\n", readget(scr), nv.dmaput, scr, getcallerpc(&scr));
349 
350 	x = 0;
351 	while(pgraph[0x00000700/4] & 0x01 && x++ < 1000000)
352 		;
353 
354 	if(x >= 1000000)
355 		iprint("idle stat %lud scrio %#p scr %#p pc %#p\n", *pgraph, scr->mmio, scr, getcallerpc(&scr));
356 }
357 
358 static void
nvresetgraphics(VGAscr * scr)359 nvresetgraphics(VGAscr *scr)
360 {
361 	ulong	surfaceFormat, patternFormat, rectFormat, lineFormat;
362 	int		pitch, i;
363 
364 	pitch = scr->gscreen->width*BY2WD;
365 
366 	/*
367 	 * DMA is at the end of the virtual window,
368 	 * but we might have cut it short when mapping it.
369 	 */
370 	if(nv.dmabase == nil){
371 		if(scr->storage <= scr->apsize)
372 			nv.dmabase = (ulong*)((uchar*)scr->vaddr + scr->storage - 128*1024);
373 		else{
374 			nv.dmabase = (void*)vmap(scr->paddr + scr->storage - 128*1024, 128*1024);
375 			if(nv.dmabase == 0){
376 				hwaccel = 0;
377 				hwblank = 0;
378 				print("vmap nvidia dma failed\n");
379 				return;
380 			}
381 		}
382 	}
383 
384 	for(i=0; i<SKIPS; i++)
385 		nv.dmabase[i] = 0x00000000;
386 
387 	nv.dmabase[0x0 + SKIPS] = 0x00040000;
388 	nv.dmabase[0x1 + SKIPS] = 0x80000010;
389 	nv.dmabase[0x2 + SKIPS] = 0x00042000;
390 	nv.dmabase[0x3 + SKIPS] = 0x80000011;
391 	nv.dmabase[0x4 + SKIPS] = 0x00044000;
392 	nv.dmabase[0x5 + SKIPS] = 0x80000012;
393 	nv.dmabase[0x6 + SKIPS] = 0x00046000;
394 	nv.dmabase[0x7 + SKIPS] = 0x80000013;
395 	nv.dmabase[0x8 + SKIPS] = 0x00048000;
396 	nv.dmabase[0x9 + SKIPS] = 0x80000014;
397 	nv.dmabase[0xA + SKIPS] = 0x0004A000;
398 	nv.dmabase[0xB + SKIPS] = 0x80000015;
399 	nv.dmabase[0xC + SKIPS] = 0x0004C000;
400 	nv.dmabase[0xD + SKIPS] = 0x80000016;
401 	nv.dmabase[0xE + SKIPS] = 0x0004E000;
402 	nv.dmabase[0xF + SKIPS] = 0x80000017;
403 
404 	nv.dmaput = 0;
405 	nv.dmacurrent = 16 + SKIPS;
406 	nv.dmamax = 8191;
407 	nv.dmafree = nv.dmamax - nv.dmacurrent;
408 
409 	switch(scr->gscreen->depth) {
410 	case 32:
411 	case 24:
412 		surfaceFormat = SURFACE_FORMAT_DEPTH24;
413 		patternFormat = PATTERN_FORMAT_DEPTH24;
414 		rectFormat = RECT_FORMAT_DEPTH24;
415 		lineFormat = LINE_FORMAT_DEPTH24;
416 		break;
417 	case 16:
418 	case 15:
419 		surfaceFormat = SURFACE_FORMAT_DEPTH16;
420 		patternFormat = PATTERN_FORMAT_DEPTH16;
421 		rectFormat = RECT_FORMAT_DEPTH16;
422 		lineFormat = LINE_FORMAT_DEPTH16;
423 		break;
424 	default:
425 		surfaceFormat = SURFACE_FORMAT_DEPTH8;
426 		patternFormat = PATTERN_FORMAT_DEPTH8;
427 		rectFormat = RECT_FORMAT_DEPTH8;
428 		lineFormat = LINE_FORMAT_DEPTH8;
429 		break;
430 	}
431 
432 	nvdmastart(scr, SURFACE_FORMAT, 4);
433 	nvdmanext(surfaceFormat);
434 	nvdmanext(pitch | (pitch << 16));
435 	nvdmanext(0);
436 	nvdmanext(0);
437 
438 	nvdmastart(scr, PATTERN_FORMAT, 1);
439 	nvdmanext(patternFormat);
440 
441 	nvdmastart(scr, RECT_FORMAT, 1);
442 	nvdmanext(rectFormat);
443 
444 	nvdmastart(scr, LINE_FORMAT, 1);
445 	nvdmanext(lineFormat);
446 
447 	nvdmastart(scr, PATTERN_COLOR_0, 4);
448 	nvdmanext(~0);
449 	nvdmanext(~0);
450 	nvdmanext(~0);
451 	nvdmanext(~0);
452 
453 	nvdmastart(scr, ROP_SET, 1);
454 	nvdmanext(0xCC);
455 
456 	nvdmakickoff(scr);
457 	waitforidle(scr);
458 }
459 
460 
461 static int
nvidiahwfill(VGAscr * scr,Rectangle r,ulong sval)462 nvidiahwfill(VGAscr *scr, Rectangle r, ulong sval)
463 {
464 	nvdmastart(scr, RECT_SOLID_COLOR, 1);
465 	nvdmanext(sval);
466 
467 	nvdmastart(scr, RECT_SOLID_RECTS(0), 2);
468 	nvdmanext((r.min.x << 16) | r.min.y);
469 	nvdmanext((Dx(r) << 16) | Dy(r));
470 
471 	//if ( (Dy(r) * Dx(r)) >= 512)
472 		nvdmakickoff(scr);
473 
474 	waitforidle(scr);
475 
476 	return 1;
477 }
478 
479 static int
nvidiahwscroll(VGAscr * scr,Rectangle r,Rectangle sr)480 nvidiahwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
481 {
482 	nvdmastart(scr, BLIT_POINT_SRC, 3);
483 	nvdmanext((sr.min.y << 16) | sr.min.x);
484 	nvdmanext((r.min.y << 16) | r.min.x);
485 	nvdmanext((Dy(r) << 16) | Dx(r));
486 
487 	//if ( (Dy(r) * Dx(r)) >= 512)
488 		nvdmakickoff(scr);
489 
490 	waitforidle(scr);
491 
492 	return 1;
493 }
494 
495 void
nvidiablank(VGAscr *,int blank)496 nvidiablank(VGAscr*, int blank)
497 {
498 	uchar seq1, crtc1A;
499 
500 	seq1 = vgaxi(Seqx, 1) & ~0x20;
501 	crtc1A = vgaxi(Crtx, 0x1A) & ~0xC0;
502 
503 	if(blank){
504 		seq1 |= 0x20;
505 //		crtc1A |= 0xC0;
506 		crtc1A |= 0x80;
507 	}
508 
509 	vgaxo(Seqx, 1, seq1);
510 	vgaxo(Crtx, 0x1A, crtc1A);
511 }
512 
513 static void
nvidiadrawinit(VGAscr * scr)514 nvidiadrawinit(VGAscr *scr)
515 {
516 	nvresetgraphics(scr);
517 	scr->blank = nvidiablank;
518 	hwblank = 1;
519 	scr->fill = nvidiahwfill;
520 	scr->scroll = nvidiahwscroll;
521 }
522 
523 VGAdev vganvidiadev = {
524 	"nvidia",
525 
526 	nvidiaenable,
527 	nil,
528 	nil,
529 	nvidialinear,
530 	nvidiadrawinit,
531 };
532 
533 VGAcur vganvidiacur = {
534 	"nvidiahwgc",
535 
536 	nvidiacurenable,
537 	nvidiacurdisable,
538 	nvidiacurload,
539 	nvidiacurmove,
540 };
541