Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * ATI Radeon [789]XXX vga driver
3
 * see /sys/src/cmd/aux/vga/radeon.c
4
 */
5
#include "u.h"
6
#include "../port/lib.h"
7
#include "mem.h"
8
#include "dat.h"
9
#include "fns.h"
10
#include "io.h"
11
#include "../port/error.h"
12
 
13
#define Image	IMAGE
14
#include <draw.h>
15
#include <memdraw.h>
16
#include <cursor.h>
17
#include "screen.h"
18
 
19
#include "/sys/src/cmd/aux/vga/radeon.h"	/* ugh */
20
 
21
/* #define HW_ACCEL */
22
 
23
enum {
24
	Kilo	= 1024,
25
	Meg	= Kilo * Kilo,
26
};
27
 
28
static Pcidev*
29
radeonpci(void)
30
{
31
	static Pcidev *p = nil;
32
	struct pciids *ids;
33
 
34
	while ((p = pcimatch(p, ATI_PCIVID, 0)) != nil)
35
		for (ids = radeon_pciids; ids->did; ids++)
36
			if (ids->did == p->did)
37
				return p;
38
	return nil;
39
}
40
 
41
/* mmio access */
42
 
43
static void
44
OUTREG8(ulong mmio, ulong offset, uchar val)
45
{
46
	((uchar*)KADDR((mmio + offset)))[0] = val;
47
}
48
 
49
static void
50
OUTREG(ulong mmio, ulong offset, ulong val)
51
{
52
	((ulong*)KADDR((mmio + offset)))[0] = val;
53
}
54
 
55
static ulong
56
INREG(ulong mmio, ulong offset)
57
{
58
	return ((ulong*)KADDR((mmio + offset)))[0];
59
}
60
 
61
static void
62
OUTREGP(ulong mmio, ulong offset, ulong val, ulong mask)
63
{
64
	OUTREG(mmio, offset, (INREG(mmio, offset) & mask) | val);
65
}
66
 
67
static void
68
OUTPLL(ulong mmio, ulong offset, ulong val)
69
{
70
	OUTREG8(mmio, CLOCK_CNTL_INDEX, (offset & 0x3f) | PLL_WR_EN);
71
	OUTREG(mmio, CLOCK_CNTL_DATA, val);
72
}
73
 
74
static ulong
75
INPLL(ulong mmio, ulong offset)
76
{
77
	OUTREG8(mmio, CLOCK_CNTL_INDEX, offset & 0x3f);
78
	return INREG(mmio, CLOCK_CNTL_DATA);
79
}
80
 
81
static void
82
OUTPLLP(ulong mmio, ulong offset, ulong val, ulong mask)
83
{
84
	OUTPLL(mmio, offset, (INPLL(mmio, offset) & mask) | val);
85
}
86
 
87
static void
88
radeonlinear(VGAscr *, int, int)
89
{
90
}
91
 
92
static void
93
radeonenable(VGAscr *scr)
94
{
95
	Pcidev *p;
96
 
97
	if (scr->mmio)
98
		return;
99
	p = radeonpci();
100
	if (p == nil)
101
		return;
102
	scr->id = p->did;
103
	scr->pci = p;
104
 
105
	scr->mmio = vmap(p->mem[2].bar & ~0x0f, p->mem[2].size);
106
	if(scr->mmio == 0)
107
		return;
108
	addvgaseg("radeonmmio", p->mem[2].bar & ~0x0f, p->mem[2].size);
109
 
110
	vgalinearpci(scr);
111
	if(scr->apsize)
112
		addvgaseg("radeonscreen", scr->paddr, scr->apsize);
113
}
114
 
115
static void
116
radeoncurload(VGAscr *scr, Cursor *curs)
117
{
118
	int x, y;
119
	ulong *p;
120
 
121
	if(scr->mmio == nil)
122
		return;
123
 
124
	p = (ulong*)KADDR(scr->storage);
125
 
126
	for(y = 0; y < 64; y++){
127
		int cv, sv;
128
 
129
		if (y < 16) {
130
			cv = curs->clr[2*y] << 8 | curs->clr[2*y+1];
131
			sv = curs->set[2*y] << 8 | curs->set[2*y+1];
132
		} else
133
			cv = sv = 0;
134
 
135
		for(x = 0; x < 64; x++){
136
			ulong col = 0;
137
			int c, s;
138
 
139
			if (x < 16) {
140
				c = (cv >> (15 - x)) & 1;
141
				s = (sv >> (15 - x)) & 1;
142
			} else
143
				c = s = 0;
144
 
145
			switch(c | s<<1) {
146
			case 0:
147
				col = 0;
148
				break;
149
			case 1:
150
				col = ~0ul;		/* white */
151
				break;
152
			case 2:
153
			case 3:
154
				col = 0xff000000;	/* black */
155
				break;
156
			}
157
 
158
			*p++ = col;
159
		}
160
	}
161
 
162
	scr->offset.x = curs->offset.x;
163
	scr->offset.y = curs->offset.y;
164
}
165
 
166
static int
167
radeoncurmove(VGAscr *scr, Point p)
168
{
169
	int x, y, ox, oy;
170
	static ulong storage = 0;
171
 
172
	if(scr->mmio == nil)
173
		return 1;
174
 
175
	if (storage == 0)
176
		storage = scr->apsize - 1*Meg;
177
 
178
	x = p.x + scr->offset.x;
179
	y = p.y + scr->offset.y;
180
	ox = oy = 0;
181
 
182
	if (x < 0) {
183
		ox = -x - 1;
184
		x = 0;
185
	}
186
	if (y < 0) {
187
		oy = -y - 1;
188
		y = 0;
189
	}
190
 
191
	OUTREG((ulong)scr->mmio, CUR_OFFSET, storage + oy * 256);
192
	OUTREG((ulong)scr->mmio, CUR_HORZ_VERT_OFF,
193
		(ox & 0x7fff) << 16 | (oy & 0x7fff));
194
	OUTREG((ulong)scr->mmio, CUR_HORZ_VERT_POSN,
195
		(x & 0x7fff) << 16 | (y & 0x7fff));
196
	return 0;
197
}
198
 
199
static void
200
radeoncurdisable(VGAscr *scr)
201
{
202
	if(scr->mmio == nil)
203
		return;
204
	OUTREGP((ulong)scr->mmio, CRTC_GEN_CNTL, 0, ~CRTC_CUR_EN);
205
}
206
 
207
static void
208
radeoncurenable(VGAscr *scr)
209
{
210
	ulong storage;
211
 
212
	if(scr->mmio == 0)
213
		return;
214
 
215
	radeoncurdisable(scr);
216
	storage = scr->apsize - 1*Meg;
217
	scr->storage = (ulong)KADDR(scr->paddr + storage);
218
	radeoncurload(scr, &arrow);
219
	radeoncurmove(scr, ZP);
220
 
221
	OUTREGP((ulong)scr->mmio, CRTC_GEN_CNTL, CRTC_CUR_EN | 2<<20,
222
		~(CRTC_CUR_EN | 3<<20));
223
}
224
 
225
/* hw blank */
226
 
227
static void
228
radeonblank(VGAscr* scr, int blank)
229
{
230
	ulong mask;
231
	char *cp;
232
 
233
	if (scr->mmio == 0)
234
		return;
235
 
236
//	iprint("radeon: hwblank(%d)\n", blank);
237
 
238
	mask = CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | CRTC_VSYNC_DIS;
239
	if (blank == 0) {
240
		OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, 0, ~mask);
241
		return;
242
	}
243
 
244
	cp = getconf("*dpms");
245
	if (cp) {
246
		if (strcmp(cp, "standby") == 0)
247
			OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL,
248
				CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS, ~mask);
249
		else if (strcmp(cp, "suspend") == 0)
250
			OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL,
251
				CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS, ~mask);
252
		else if (strcmp(cp, "off") == 0)
253
			OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, mask, ~mask);
254
		return;
255
	}
256
 
257
	OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, mask, ~mask);
258
}
259
 
260
/* hw acceleration */
261
 
262
static void
263
radeonwaitfifo(VGAscr *scr, int entries)
264
{
265
	int i;
266
 
267
	for (i = 0; i < 2000000; i++)
268
		if (INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_FIFOCNT_MASK >=
269
		    entries)
270
			return;
271
	iprint("radeon: fifo timeout\n");
272
}
273
 
274
static void
275
radeonwaitidle(VGAscr *scr)
276
{
277
	radeonwaitfifo(scr, 64);
278
 
279
	for (; ; ) {
280
		int i;
281
 
282
		for (i = 0; i < 2000000; i++)
283
			if (!(INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_ACTIVE))
284
				return;
285
 
286
		iprint("radeon: idle timed out: %uld entries, stat=0x%.8ulx\n",
287
			INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_FIFOCNT_MASK,
288
			INREG((ulong)scr->mmio, RBBM_STATUS));
289
	}
290
}
291
 
292
static ulong dp_gui_master_cntl = 0;
293
 
294
static int
295
radeonfill(VGAscr *scr, Rectangle r, ulong color)
296
{
297
	if (scr->mmio == nil)
298
		return 0;
299
 
300
	radeonwaitfifo(scr, 6);
301
	OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL,
302
		dp_gui_master_cntl | GMC_BRUSH_SOLID_COLOR |
303
		GMC_SRC_DATATYPE_COLOR | ROP3_P);
304
	OUTREG((ulong)scr->mmio, DP_BRUSH_FRGD_CLR, color);
305
	OUTREG((ulong)scr->mmio, DP_WRITE_MASK, ~0ul);
306
	OUTREG((ulong)scr->mmio, DP_CNTL,
307
		DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
308
	OUTREG((ulong)scr->mmio, DST_Y_X, r.min.y << 16 | r.min.x);
309
	OUTREG((ulong)scr->mmio, DST_WIDTH_HEIGHT, Dx(r) << 16 | Dy(r));
310
 
311
	radeonwaitidle(scr);
312
	return 1;
313
}
314
 
315
static int
316
radeonscroll(VGAscr*scr, Rectangle dst, Rectangle src)
317
{
318
	int xs, ys, xd, yd, w, h;
319
	ulong dp_cntl = 0x20;
320
 
321
	if (scr->mmio == nil)
322
		return 0;
323
 
324
	// iprint("radeon: hwscroll(dst:%R, src:%R)\n", dst, src);
325
 
326
	xd = dst.min.x;
327
	yd = dst.min.y;
328
	xs = src.min.x;
329
	ys = src.min.y;
330
	w = Dx(dst);
331
	h = Dy(dst);
332
 
333
	if (ys < yd) {
334
		ys += h - 1;
335
		yd += h - 1;
336
	} else
337
		dp_cntl |= DST_Y_TOP_TO_BOTTOM;
338
 
339
	if (xs < xd) {
340
		xs += w - 1;
341
		xd += w - 1;
342
	} else
343
		dp_cntl |= DST_X_LEFT_TO_RIGHT;
344
 
345
	radeonwaitfifo(scr, 6);
346
	OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL, dp_gui_master_cntl |
347
		GMC_BRUSH_NONE | GMC_SRC_DATATYPE_COLOR | DP_SRC_SOURCE_MEMORY |
348
		ROP3_S);
349
	OUTREG((ulong)scr->mmio, DP_WRITE_MASK, ~0ul);
350
	OUTREG((ulong)scr->mmio, DP_CNTL, dp_cntl);
351
	OUTREG((ulong)scr->mmio, SRC_Y_X, ys << 16 | xs);
352
	OUTREG((ulong)scr->mmio, DST_Y_X, yd << 16 | xd);
353
	OUTREG((ulong)scr->mmio, DST_WIDTH_HEIGHT, w << 16 | h);
354
 
355
	radeonwaitidle(scr);
356
 
357
	// iprint("radeon: hwscroll(xs=%d ys=%d xd=%d yd=%d w=%d h=%d)\n",
358
	//	xs, ys, xd, yd, w, h);
359
	return 1;
360
}
361
 
362
static void
363
radeondrawinit(VGAscr*scr)
364
{
365
	ulong bpp, dtype, i, pitch, clock_cntl_index, mclk_cntl, rbbm_soft_reset;
366
 
367
	if (scr->mmio == 0)
368
		return;
369
 
370
	switch (scr->gscreen->depth) {
371
	case 6:
372
	case 8:
373
		dtype = 2;
374
		bpp = 1;
375
		break;
376
	case 15:
377
		dtype = 3;
378
		bpp = 2;
379
		break;
380
	case 16:
381
		dtype = 4;
382
		bpp = 2;
383
		break;
384
	case 32:
385
		dtype = 6;
386
		bpp = 4;
387
		break;
388
	default:
389
		return;
390
	}
391
 
392
	/* disable 3D */
393
	OUTREG((ulong)scr->mmio, RB3D_CNTL, 0);
394
 
395
	/* flush engine */
396
	OUTREGP((ulong)scr->mmio, RB2D_DSTCACHE_CTLSTAT,
397
		RB2D_DC_FLUSH_ALL, ~RB2D_DC_FLUSH_ALL);
398
	for (i = 0; i < 2000000; i++)
399
		if (!(INREG((ulong)scr->mmio, RB2D_DSTCACHE_CTLSTAT) &
400
		    RB2D_DC_BUSY))
401
			break;
402
 
403
	/* reset 2D engine */
404
	clock_cntl_index = INREG((ulong)scr->mmio, CLOCK_CNTL_INDEX);
405
 
406
	mclk_cntl = INPLL((ulong)scr->mmio, MCLK_CNTL);
407
	OUTPLL((ulong)scr->mmio, MCLK_CNTL, mclk_cntl | FORCEON_MCLKA |
408
		FORCEON_MCLKB | FORCEON_YCLKA | FORCEON_YCLKB | FORCEON_MC |
409
		FORCEON_AIC);
410
	rbbm_soft_reset = INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
411
 
412
	OUTREG((ulong)scr->mmio, RBBM_SOFT_RESET, rbbm_soft_reset |
413
		SOFT_RESET_CP | SOFT_RESET_HI | SOFT_RESET_SE | SOFT_RESET_RE |
414
		SOFT_RESET_PP | SOFT_RESET_E2 | SOFT_RESET_RB);
415
	INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
416
	OUTREG((ulong)scr->mmio, RBBM_SOFT_RESET, rbbm_soft_reset &
417
		~(SOFT_RESET_CP | SOFT_RESET_HI | SOFT_RESET_SE | SOFT_RESET_RE |
418
		SOFT_RESET_PP | SOFT_RESET_E2 | SOFT_RESET_RB));
419
	INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
420
 
421
	OUTPLL((ulong)scr->mmio, MCLK_CNTL, mclk_cntl);
422
	OUTREG((ulong)scr->mmio, CLOCK_CNTL_INDEX, clock_cntl_index);
423
 
424
	/* init 2D engine */
425
	radeonwaitfifo(scr, 1);
426
	OUTREG((ulong)scr->mmio, RB2D_DSTCACHE_MODE, 0);
427
 
428
	pitch = Dx(scr->gscreen->r) * bpp;
429
	radeonwaitfifo(scr, 4);
430
	OUTREG((ulong)scr->mmio, DEFAULT_PITCH, pitch);
431
	OUTREG((ulong)scr->mmio, DST_PITCH, pitch);
432
	OUTREG((ulong)scr->mmio, SRC_PITCH, pitch);
433
	OUTREG((ulong)scr->mmio, DST_PITCH_OFFSET_C, 0);
434
 
435
	radeonwaitfifo(scr, 3);
436
	OUTREG((ulong)scr->mmio, DEFAULT_OFFSET, 0);
437
	OUTREG((ulong)scr->mmio, DST_OFFSET, 0);
438
	OUTREG((ulong)scr->mmio, SRC_OFFSET, 0);
439
 
440
	radeonwaitfifo(scr, 1);
441
	OUTREGP((ulong)scr->mmio, DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
442
 
443
	radeonwaitfifo(scr, 1);
444
	OUTREG((ulong)scr->mmio, DEFAULT_SC_BOTTOM_RIGHT,
445
		DEFAULT_SC_RIGHT_MAX | DEFAULT_SC_BOTTOM_MAX);
446
 
447
	dp_gui_master_cntl = dtype << GMC_DST_DATATYPE_SHIFT |
448
		GMC_SRC_PITCH_OFFSET_CNTL | GMC_DST_PITCH_OFFSET_CNTL |
449
		GMC_CLR_CMP_CNTL_DIS;
450
	radeonwaitfifo(scr, 1);
451
	OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL,
452
	    dp_gui_master_cntl | GMC_BRUSH_SOLID_COLOR | GMC_SRC_DATATYPE_COLOR);
453
 
454
	radeonwaitfifo(scr, 7);
455
	OUTREG((ulong)scr->mmio, DST_LINE_START,    0);
456
	OUTREG((ulong)scr->mmio, DST_LINE_END,      0);
457
	OUTREG((ulong)scr->mmio, DP_BRUSH_FRGD_CLR, ~0ul);
458
	OUTREG((ulong)scr->mmio, DP_BRUSH_BKGD_CLR, 0);
459
	OUTREG((ulong)scr->mmio, DP_SRC_FRGD_CLR,   ~0ul);
460
	OUTREG((ulong)scr->mmio, DP_SRC_BKGD_CLR,   0);
461
	OUTREG((ulong)scr->mmio, DP_WRITE_MASK,     ~0ul);
462
 
463
	radeonwaitidle(scr);
464
 
465
	scr->fill = radeonfill;
466
	scr->scroll = radeonscroll;
467
	hwaccel = 1;
468
 
469
	scr->blank = radeonblank;
470
	hwblank = 1;
471
}
472
 
473
/* hw overlay */
474
 
475
static void
476
radeonovlctl(VGAscr *scr, Chan *c, void *data, int len)
477
{
478
	USED(scr, c, data, len);
479
}
480
 
481
static int
482
radeonovlwrite(VGAscr *scr, void *data, int len, vlong opt)
483
{
484
	USED(scr, data, len, opt);
485
	return -1;
486
}
487
 
488
static void
489
radeonflush(VGAscr *scr, Rectangle r)
490
{
491
	USED(scr, r);
492
}
493
 
494
/* Export */
495
 
496
VGAdev vgaradeondev = {
497
	"radeon",
498
 
499
	radeonenable,
500
	0, 				/* disable */
501
	0, 				/* page */
502
	radeonlinear,
503
 
504
	radeondrawinit,
505
#ifdef HW_ACCEL
506
	radeonfill,
507
 
508
	radeonovlctl,
509
	radeonovlwrite,
510
	radeonflush,
511
#endif
512
};
513
VGAcur vgaradeoncur = {
514
	"radeonhwgc",
515
	radeoncurenable,
516
	radeoncurdisable,
517
	radeoncurload,
518
	radeoncurmove,
519
 
520
};