]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vgaradeon.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / 9 / pc / vgaradeon.c
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         0                               /* doespanning */
520 };