vgamga4xx.c 11 KB

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