vgaradeon.c 10 KB

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