vgamga4xx.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. * Matrox G200, G400 and G450.
  3. * see /sys/src/cmd/aux/vga/mga4xx.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. enum {
  18. MATROX = 0x102B,
  19. MGA4xx = 0x0525,
  20. MGA200 = 0x0521,
  21. FCOL = 0x1c24,
  22. FXRIGHT = 0x1cac,
  23. FXLEFT = 0x1ca8,
  24. YDST = 0x1c90,
  25. YLEN = 0x1c5c,
  26. DWGCTL = 0x1c00,
  27. DWG_TRAP = 0x04,
  28. DWG_BITBLT = 0x08,
  29. DWG_ILOAD = 0x09,
  30. DWG_LINEAR = 0x0080,
  31. DWG_SOLID = 0x0800,
  32. DWG_ARZERO = 0x1000,
  33. DWG_SGNZERO = 0x2000,
  34. DWG_SHIFTZERO = 0x4000,
  35. DWG_REPLACE = 0x000C0000,
  36. DWG_REPLACE2 = (DWG_REPLACE | 0x40),
  37. DWG_XOR = 0x00060010,
  38. DWG_BFCOL = 0x04000000,
  39. DWG_BMONOWF = 0x08000000,
  40. DWG_TRANSC = 0x40000000,
  41. SRCORG = 0x2cb4,
  42. PITCH = 0x1c8c,
  43. DSTORG = 0x2cb8,
  44. PLNWRT = 0x1c1c,
  45. ZORG = 0x1c0c,
  46. MACCESS = 0x1c04,
  47. STATUS = 0x1e14,
  48. FXBNDRY = 0x1C84,
  49. CXBNDRY = 0x1C80,
  50. YTOP = 0x1C98,
  51. YBOT = 0x1C9C,
  52. YDSTLEN = 0x1C88,
  53. AR0 = 0x1C60,
  54. AR1 = 0x1C64,
  55. AR2 = 0x1C68,
  56. AR3 = 0x1C6C,
  57. AR4 = 0x1C70,
  58. AR5 = 0x1C74,
  59. SGN = 0x1C58,
  60. SGN_SCANLEFT = 1,
  61. SGN_SCANRIGHT = 0,
  62. SGN_SDY_POSITIVE = 0,
  63. SGN_SDY_NEGATIVE = 4,
  64. GO = 0x0100,
  65. FIFOSTATUS = 0x1E10,
  66. CACHEFLUSH = 0x1FFF,
  67. CRTCEXTIDX = 0x1FDE, /* CRTC Extension Index */
  68. CRTCEXTDATA = 0x1FDF, /* CRTC Extension Data */
  69. FILL_OPERAND = 0x800c7804,
  70. };
  71. static Pcidev*
  72. mgapcimatch(void)
  73. {
  74. Pcidev* p;
  75. p = pcimatch(nil, MATROX, MGA4xx);
  76. if (p == nil)
  77. p = pcimatch(nil, MATROX, MGA200);
  78. return p;
  79. }
  80. static void
  81. mgawrite8(VGAscr* scr, int index, uchar val)
  82. {
  83. ((uchar*)scr->mmio)[index] = val;
  84. }
  85. static uchar
  86. mgaread8(VGAscr* scr, int index)
  87. {
  88. return ((uchar*)scr->mmio)[index];
  89. }
  90. static uchar
  91. crtcextset(VGAscr* scr, int index, uchar set, uchar clr)
  92. {
  93. uchar tmp;
  94. mgawrite8(scr, CRTCEXTIDX, index);
  95. tmp = mgaread8(scr, CRTCEXTDATA);
  96. mgawrite8(scr, CRTCEXTIDX, index);
  97. mgawrite8(scr, CRTCEXTDATA, (tmp & ~clr) | set);
  98. return tmp;
  99. }
  100. static void
  101. mga4xxenable(VGAscr* scr)
  102. {
  103. Pcidev * pci;
  104. int size;
  105. int i, n, k;
  106. uchar * p;
  107. uchar x[16];
  108. uchar crtcext3;
  109. if(scr->mmio)
  110. return;
  111. pci = mgapcimatch();
  112. if(pci == nil)
  113. return;
  114. scr->mmio = vmap(pci->mem[1].bar&~0x0F, 16*1024);
  115. if(scr->mmio == nil)
  116. return;
  117. addvgaseg("mga4xxmmio", pci->mem[1].bar&~0x0F, pci->mem[1].size);
  118. /* need to map frame buffer here too, so vga can find memory size */
  119. if(pci->did == MGA4xx)
  120. size = 32*MB;
  121. else
  122. size = 8*MB;
  123. vgalinearaddr(scr, pci->mem[0].bar&~0x0F, size);
  124. if(scr->paddr){
  125. /* Find out how much memory is here, some multiple of 2 MB */
  126. /* First Set MGA Mode ... */
  127. crtcext3 = crtcextset(scr, 3, 0x80, 0x00);
  128. p = scr->vaddr;
  129. n = (size / MB) / 2;
  130. for (i = 0; i < n; i++) {
  131. k = (2*i+1)*MB;
  132. p[k] = 0;
  133. p[k] = i+1;
  134. *((uchar*)scr->mmio + CACHEFLUSH) = 0;
  135. x[i] = p[k];
  136. }
  137. for(i = 1; i < n; i++)
  138. if(x[i] != i+1)
  139. break;
  140. scr->apsize = 2*i*MB; /* sketchy */
  141. addvgaseg("mga4xxscreen", scr->paddr, scr->apsize);
  142. crtcextset(scr, 3, crtcext3, 0xff);
  143. }
  144. }
  145. enum {
  146. Index = 0x00, /* Index */
  147. Data = 0x0A, /* Data */
  148. Cxlsb = 0x0C, /* Cursor X LSB */
  149. Cxmsb = 0x0D, /* Cursor X MSB */
  150. Cylsb = 0x0E, /* Cursor Y LSB */
  151. Cymsb = 0x0F, /* Cursor Y MSB */
  152. Icuradrl = 0x04, /* Cursor Base Address Low */
  153. Icuradrh = 0x05, /* Cursor Base Address High */
  154. Icctl = 0x06, /* Indirect Cursor Control */
  155. };
  156. static void
  157. dac4xxdisable(VGAscr* scr)
  158. {
  159. uchar * dac4xx;
  160. if(scr->mmio == 0)
  161. return;
  162. dac4xx = (uchar*)scr->mmio+0x3C00;
  163. *(dac4xx+Index) = Icctl;
  164. *(dac4xx+Data) = 0x00;
  165. }
  166. static void
  167. dac4xxload(VGAscr* scr, Cursor* curs)
  168. {
  169. int y;
  170. uchar * p;
  171. uchar * dac4xx;
  172. if(scr->mmio == 0)
  173. return;
  174. dac4xx = (uchar*)scr->mmio+0x3C00;
  175. dac4xxdisable(scr);
  176. p = scr->vaddr;
  177. for(y = 0; y < 64; y++){
  178. *p++ = 0; *p++ = 0; *p++ = 0;
  179. *p++ = 0; *p++ = 0; *p++ = 0;
  180. if(y <16){
  181. *p++ = curs->set[1+y*2]|curs->clr[1+2*y];
  182. *p++ = curs->set[y*2]|curs->clr[2*y];
  183. } else{
  184. *p++ = 0; *p++ = 0;
  185. }
  186. *p++ = 0; *p++ = 0; *p++ = 0;
  187. *p++ = 0; *p++ = 0; *p++ = 0;
  188. if(y <16){
  189. *p++ = curs->set[1+y*2];
  190. *p++ = curs->set[y*2];
  191. } else{
  192. *p++ = 0; *p++ = 0;
  193. }
  194. }
  195. scr->offset.x = 64 + curs->offset.x;
  196. scr->offset.y = 64 + curs->offset.y;
  197. *(dac4xx+Index) = Icctl;
  198. *(dac4xx+Data) = 0x03;
  199. }
  200. static int
  201. dac4xxmove(VGAscr* scr, Point p)
  202. {
  203. int x, y;
  204. uchar * dac4xx;
  205. if(scr->mmio == 0)
  206. return 1;
  207. dac4xx = (uchar*)scr->mmio + 0x3C00;
  208. x = p.x + scr->offset.x;
  209. y = p.y + scr->offset.y;
  210. *(dac4xx+Cxlsb) = x & 0xFF;
  211. *(dac4xx+Cxmsb) = (x>>8) & 0x0F;
  212. *(dac4xx+Cylsb) = y & 0xFF;
  213. *(dac4xx+Cymsb) = (y>>8) & 0x0F;
  214. return 0;
  215. }
  216. static void
  217. dac4xxenable(VGAscr* scr)
  218. {
  219. uchar * dac4xx;
  220. ulong storage;
  221. if(scr->mmio == 0)
  222. return;
  223. dac4xx = (uchar*)scr->mmio+0x3C00;
  224. dac4xxdisable(scr);
  225. storage = (scr->apsize - 4096) & ~0x3ff;
  226. *(dac4xx+Index) = Icuradrl;
  227. *(dac4xx+Data) = 0xff & (storage >> 10);
  228. *(dac4xx+Index) = Icuradrh;
  229. *(dac4xx+Data) = 0xff & (storage >> 18);
  230. scr->storage = (ulong)scr->vaddr + storage;
  231. /* Show X11-Like Cursor */
  232. *(dac4xx+Index) = Icctl;
  233. *(dac4xx+Data) = 0x03;
  234. /* Cursor Color 0 : White */
  235. *(dac4xx+Index) = 0x08;
  236. *(dac4xx+Data) = 0xff;
  237. *(dac4xx+Index) = 0x09;
  238. *(dac4xx+Data) = 0xff;
  239. *(dac4xx+Index) = 0x0a;
  240. *(dac4xx+Data) = 0xff;
  241. /* Cursor Color 1 : Black */
  242. *(dac4xx+Index) = 0x0c;
  243. *(dac4xx+Data) = 0x00;
  244. *(dac4xx+Index) = 0x0d;
  245. *(dac4xx+Data) = 0x00;
  246. *(dac4xx+Index) = 0x0e;
  247. *(dac4xx+Data) = 0x00;
  248. /* Cursor Color 2 : Red */
  249. *(dac4xx+Index) = 0x10;
  250. *(dac4xx+Data) = 0xff;
  251. *(dac4xx+Index) = 0x11;
  252. *(dac4xx+Data) = 0x00;
  253. *(dac4xx+Index) = 0x12;
  254. *(dac4xx+Data) = 0x00;
  255. /*
  256. * Load, locate and enable the
  257. * 64x64 cursor in X11 mode.
  258. */
  259. dac4xxload(scr, &arrow);
  260. dac4xxmove(scr, ZP);
  261. }
  262. static void
  263. mga4xxblank(VGAscr* scr, int blank)
  264. {
  265. char * cp;
  266. uchar * mga;
  267. uchar seq1, crtcext1;
  268. /* blank = 0 -> turn screen on */
  269. /* blank = 1 -> turn screen off */
  270. if(scr->mmio == 0)
  271. return;
  272. mga = (uchar*)scr->mmio;
  273. if (blank == 0) {
  274. seq1 = 0x00;
  275. crtcext1 = 0x00;
  276. } else {
  277. seq1 = 0x20;
  278. crtcext1 = 0x10; /* Default value ... : standby */
  279. cp = getconf("*dpms");
  280. if (cp) {
  281. if (cistrcmp(cp, "standby") == 0) {
  282. crtcext1 = 0x10;
  283. } else if (cistrcmp(cp, "suspend") == 0) {
  284. crtcext1 = 0x20;
  285. } else if (cistrcmp(cp, "off") == 0) {
  286. crtcext1 = 0x30;
  287. }
  288. }
  289. }
  290. *(mga + 0x1fc4) = 1;
  291. seq1 |= *(mga + 0x1fc5) & ~0x20;
  292. *(mga + 0x1fc5) = seq1;
  293. *(mga + 0x1fde) = 1;
  294. crtcext1 |= *(mga + 0x1fdf) & ~0x30;
  295. *(mga + 0x1fdf) = crtcext1;
  296. }
  297. static void
  298. mgawrite32(uchar * mga, ulong reg, ulong val)
  299. {
  300. ulong * l;
  301. l = (ulong *)(&mga[reg]);
  302. l[0] = val;
  303. }
  304. static ulong
  305. mgaread32(uchar * mga, ulong reg)
  306. {
  307. return *((ulong *)(&mga[reg]));
  308. }
  309. static int
  310. mga4xxfill(VGAscr* scr, Rectangle r, ulong color)
  311. {
  312. uchar * mga;
  313. /* Constant Shaded Trapezoids / Rectangle Fills */
  314. if(scr->mmio == 0)
  315. return 0;
  316. mga = (uchar*)scr->mmio;
  317. mgawrite32(mga, DWGCTL, 0);
  318. mgawrite32(mga, FCOL, color);
  319. mgawrite32(mga, FXRIGHT, r.max.x);
  320. mgawrite32(mga, FXLEFT, r.min.x);
  321. mgawrite32(mga, YDST, r.min.y);
  322. mgawrite32(mga, YLEN, Dy(r));
  323. mgawrite32(mga, DWGCTL + GO, FILL_OPERAND);
  324. while (mgaread32(mga, STATUS) & 0x00010000)
  325. ;
  326. return 1;
  327. }
  328. #define mga_fifo(n) do {} while ((mgaread32(mga, FIFOSTATUS) & 0xFF) < (n))
  329. static int
  330. mga4xxscroll(VGAscr* scr, Rectangle r_dst, Rectangle r_src)
  331. {
  332. uchar * mga;
  333. ulong pitch, y;
  334. ulong width, height, start, end, scandir;
  335. int ydir;
  336. /* Two-operand Bitblts */
  337. if(scr->mmio == 0)
  338. return 0;
  339. mga = (uchar*)scr->mmio;
  340. pitch = Dx(scr->gscreen->r);
  341. mgawrite32(mga, DWGCTL, 0);
  342. scandir = 0;
  343. height = abs(Dy(r_src));
  344. width = abs(Dx(r_src));
  345. assert(height == abs(Dy(r_dst)));
  346. assert(width == abs(Dx(r_dst)));
  347. if ((r_src.min.y == r_dst.min.y) && (r_src.min.x == r_dst.min.x))
  348. {
  349. if (0)
  350. print("move x,y to x,y !\n");
  351. return 1;
  352. }
  353. ydir = 1;
  354. if (r_dst.min.y > r_src.min.y)
  355. {
  356. if (0)
  357. print("ydir = -1\n");
  358. ydir = -1;
  359. scandir |= 4; // Blit UP
  360. }
  361. if (r_dst.min.x > r_src.min.x)
  362. {
  363. if (0)
  364. print("xdir = -1\n");
  365. scandir |= 1; // Blit Left
  366. }
  367. mga_fifo(4);
  368. if (scandir)
  369. {
  370. mgawrite32(mga, DWGCTL, DWG_BITBLT | DWG_SHIFTZERO |
  371. DWG_SGNZERO | DWG_BFCOL | DWG_REPLACE);
  372. mgawrite32(mga, SGN, scandir);
  373. } else
  374. {
  375. mgawrite32(mga, DWGCTL, DWG_BITBLT | DWG_SHIFTZERO |
  376. DWG_BFCOL | DWG_REPLACE);
  377. }
  378. mgawrite32(mga, AR5, ydir * pitch);
  379. width--;
  380. start = end = r_src.min.x + (r_src.min.y * pitch);
  381. if ((scandir & 1) == 1)
  382. {
  383. start += width;
  384. } else
  385. {
  386. end += width;
  387. }
  388. y = r_dst.min.y;
  389. if ((scandir & 4) == 4)
  390. {
  391. start += (height - 1) * pitch;
  392. end += (height - 1) * pitch;
  393. y += (height - 1);
  394. }
  395. mga_fifo(4);
  396. mgawrite32(mga, AR0, end);
  397. mgawrite32(mga, AR3, start);
  398. mgawrite32(mga, FXBNDRY, ((r_dst.min.x+width)<<16) | r_dst.min.x);
  399. mgawrite32(mga, YDSTLEN + GO, (y << 16) | height);
  400. if (1)
  401. {
  402. while (mgaread32(mga, STATUS) & 0x00010000)
  403. ;
  404. }
  405. return 1;
  406. }
  407. static void
  408. mga4xxdrawinit(VGAscr* scr)
  409. {
  410. uchar * mga;
  411. Pcidev* p;
  412. p = pcimatch(nil, MATROX, MGA4xx);
  413. if (p == nil)
  414. return ;
  415. if(scr->mmio == 0)
  416. return;
  417. mga = (uchar*)scr->mmio;
  418. mgawrite32(mga, SRCORG, 0);
  419. mgawrite32(mga, DSTORG, 0);
  420. mgawrite32(mga, ZORG, 0);
  421. mgawrite32(mga, PLNWRT, ~0);
  422. mgawrite32(mga, FCOL, 0xffff0000);
  423. mgawrite32(mga, CXBNDRY, 0xFFFF0000);
  424. mgawrite32(mga, YTOP, 0);
  425. mgawrite32(mga, YBOT, 0x01FFFFFF);
  426. mgawrite32(mga, PITCH, Dx(scr->gscreen->r) & ((1 << 13) - 1));
  427. switch(scr->gscreen->depth) {
  428. case 8:
  429. mgawrite32(mga, MACCESS, 0);
  430. break;
  431. case 32:
  432. mgawrite32(mga, MACCESS, 2);
  433. break;
  434. default:
  435. return; /* depth not supported ! */
  436. }
  437. scr->fill = mga4xxfill;
  438. scr->scroll = mga4xxscroll;
  439. scr->blank = mga4xxblank;
  440. }
  441. VGAdev vgamga4xxdev = {
  442. "mga4xx",
  443. mga4xxenable, /* enable */
  444. 0, /* disable */
  445. 0, /* page */
  446. 0, /* linear */
  447. mga4xxdrawinit,
  448. };
  449. VGAcur vgamga4xxcur = {
  450. "mga4xxhwgc",
  451. dac4xxenable,
  452. dac4xxdisable,
  453. dac4xxload,
  454. dac4xxmove,
  455. };