vgamga4xx.c 9.3 KB

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