vgaradeon.c 10 KB

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