mga2164w.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. /*
  7. * Matrox Millenium and Matrox Millenium II.
  8. * Matrox MGA-2064W, MGA-2164W 3D graphics accelerators
  9. * Texas Instruments Tvp3026 RAMDAC.
  10. */
  11. enum {
  12. Meg = 1024*1024,
  13. /* pci chip manufacturer */
  14. MATROX = 0x102B,
  15. /* pci chip device ids */
  16. MGA2064 = 0x0519,
  17. MGA2164 = 0x051B,
  18. MGA2164AGP = 0x051F,
  19. /* i/o ports */
  20. Crtcext = 0x03DE, /* CRTC Extensions */
  21. /* config space offsets */
  22. Devctrl = 0x04, /* Device Control */
  23. Option = 0x40, /* Option */
  24. /* control aperture offsets */
  25. RAMDAC = 0x3C00, /* RAMDAC registers */
  26. CACHEFLUSH = 0x1FFF,
  27. };
  28. typedef struct {
  29. Pcidev* pci;
  30. int devid;
  31. ulong membase1;
  32. ulong membase2;
  33. ulong devctrl;
  34. ulong option;
  35. uchar crtcext[6];
  36. uchar tvp[64];
  37. uchar pclk[3];
  38. uchar mclk[3];
  39. uchar lclk[3];
  40. } Mga;
  41. static uchar
  42. _tvp3026i(Vga* vga, Ctlr* ctlr, uchar reg)
  43. {
  44. Mga *mga;
  45. if(reg >= 0x10)
  46. error("%s: tvp3026io: direct reg 0x%uX out of range\n", ctlr->name, reg);
  47. if(vga->private == nil)
  48. error("%s: tvp3026io: no *mga\n", ctlr->name);
  49. mga = vga->private;
  50. return *((uchar*)(mga->membase1+RAMDAC+reg));
  51. }
  52. static void
  53. _tvp3026o(Vga* vga, Ctlr* ctlr, uchar reg, uchar data)
  54. {
  55. Mga *mga;
  56. if(reg >= 0x10)
  57. error("%s: tvp3026io: direct reg 0x%uX out of range\n", ctlr->name, reg);
  58. if(vga->private == nil)
  59. error("%s: tvp3026io: no *mga\n", ctlr->name);
  60. mga = vga->private;
  61. *((uchar*)(mga->membase1+RAMDAC+reg)) = data;
  62. }
  63. static uchar
  64. _tvp3026xi(Vga* vga, Ctlr* ctlr, uchar index)
  65. {
  66. if(index >= 0x40)
  67. error("%s: tvp3026xi: reg 0x%uX out of range\n", ctlr->name, index);
  68. _tvp3026o(vga, ctlr, 0x00, index);
  69. return _tvp3026i(vga, ctlr, 0x0A);
  70. }
  71. void
  72. _tvp3026xo(Vga* vga, Ctlr* ctlr, uchar index, uchar data)
  73. {
  74. if(index >= 0x40)
  75. error("%s: tvp3026xo: reg 0x%uX out of range\n", ctlr->name, index);
  76. _tvp3026o(vga, ctlr, 0x00, index);
  77. _tvp3026o(vga, ctlr, 0x0A, data);
  78. }
  79. static uchar
  80. crtcexti(uchar index)
  81. {
  82. uchar data;
  83. outportb(Crtcext, index);
  84. data = inportb(Crtcext+1);
  85. return data;
  86. }
  87. static void
  88. crtcexto(uchar index, uchar data)
  89. {
  90. outportb(Crtcext, index);
  91. outportb(Crtcext+1, data);
  92. }
  93. static void
  94. mapmga(Vga* vga, Ctlr* ctlr)
  95. {
  96. int f;
  97. long m;
  98. Mga *mga;
  99. if(vga->private == nil)
  100. error("%s: tvp3026io: no *mga\n", ctlr->name);
  101. mga = vga->private;
  102. f = open("#v/vgactl", OWRITE);
  103. if(f < 0)
  104. error("%s: can't open vgactl\n", ctlr->name);
  105. if(write(f, "type mga2164w", 13) != 13)
  106. error("%s: can't set mga type\n", ctlr->name);
  107. m = segattach(0, "mga2164wmmio", 0, 16*1024);
  108. if(m == -1)
  109. error("%s: can't attach mga2164wmmio segment\n", ctlr->name);
  110. mga->membase1 = m;
  111. m = segattach(0, "mga2164wscreen", 0, (mga->devid==MGA2064? 8 : 16)*Meg);
  112. if(m == -1)
  113. error("%s: can't attach mga2164wscreen segment\n", ctlr->name);
  114. mga->membase2 = m;
  115. }
  116. static void
  117. clockcalc(Vga* vga, Ctlr* ctlr, int bpp)
  118. {
  119. ulong m, n, p, q;
  120. double z, fdiff, fmindiff, fvco, fgoal;
  121. Mga *mga;
  122. USED(ctlr);
  123. mga = vga->private;
  124. /*
  125. * Look for values of n, d and p that give
  126. * the least error for
  127. * Fvco = 8*RefFreq*(65-m)/(65-n)
  128. * Fpll = Fvco/2**p
  129. * N and m are 6 bits, p is 2 bits. Constraints:
  130. * 110MHz <= Fvco <= 250MHz
  131. * 40 <= n <= 62
  132. * 1 <= m <= 62
  133. * 0 <= p <= 3
  134. */
  135. fgoal = (double)vga->f[0];
  136. fmindiff = fgoal;
  137. vga->m[0] = 0x15;
  138. vga->n[0] = 0x18;
  139. vga->p[0] = 3;
  140. for(m = 62; m > 0; m--){
  141. for(n = 62; n >= 40; n--){
  142. fvco = 8.*((double)RefFreq)*(65.-m)/(65.-n);
  143. if(fvco < 110e6 || fvco > 250e6)
  144. continue;
  145. for(p = 0; p < 4; p++){
  146. fdiff = fgoal - fvco/(1<<p);
  147. if(fdiff < 0)
  148. fdiff = -fdiff;
  149. if(fdiff < fmindiff){
  150. fmindiff = fdiff;
  151. vga->m[0] = m;
  152. vga->n[0] = n;
  153. vga->p[0] = p;
  154. }
  155. }
  156. }
  157. }
  158. mga->pclk[0] = 0xC0 | (vga->n[0] & 0x3f);
  159. mga->pclk[1] = (vga->m[0] & 0x3f);
  160. mga->pclk[2] = 0xB0 | (vga->p[0] & 0x03);
  161. /*
  162. * Now the loop clock:
  163. * m is fixed;
  164. * calculate n;
  165. * set z to the lower bound (110MHz) and calculate p and q.
  166. */
  167. vga->m[1] = 61;
  168. n = 65 - 4*(64/(vga->vmz==2*Meg? bpp*2 : bpp));
  169. fvco = (8*RefFreq*(65-vga->m[0]))/(65-vga->n[0]);
  170. vga->f[1] = fvco/(1<<vga->p[0]);
  171. z = 110e6*(65.-n)/(4.*vga->f[1]);
  172. if(z <= 16){
  173. for(p = 0; p < 4; p++){
  174. if(1<<(p+1) > z)
  175. break;
  176. }
  177. q = 0;
  178. }
  179. else{
  180. p = 3;
  181. q = (z - 16)/16 + 1;
  182. }
  183. vga->n[1] = n;
  184. vga->p[1] = p;
  185. vga->q[1] = q;
  186. mga->lclk[0] = 0xC0 | (vga->n[1] & 0x3f);
  187. mga->lclk[1] = (vga->m[1] & 0x3f);
  188. mga->lclk[2] = 0xF0 | (vga->p[1] & 0x03);
  189. mga->tvp[0x39] = 0x38 | q;
  190. }
  191. static void
  192. snarf(Vga* vga, Ctlr* ctlr)
  193. {
  194. int i, k, n;
  195. uchar *p, x[8];
  196. Pcidev *pci;
  197. Mga *mga;
  198. if(vga->private == nil) {
  199. pci = pcimatch(nil, MATROX, MGA2164AGP);
  200. if(pci == nil)
  201. pci = pcimatch(nil, MATROX, MGA2164);
  202. if(pci == nil)
  203. pci = pcimatch(nil, MATROX, MGA2064);
  204. if(pci == nil)
  205. error("%s: no Pcidev with Vid=0x102B, Did=0x051[9BF] or 0x521\n", ctlr->name);
  206. vga->private = alloc(sizeof(Mga));
  207. mga = (Mga*)vga->private;
  208. mga->devid = pci->did;
  209. mga->pci = pci;
  210. mapmga(vga, ctlr);
  211. }
  212. else {
  213. mga = (Mga*)vga->private;
  214. pci = mga->pci;
  215. }
  216. for(i = 0; i < 0x06; i++)
  217. mga->crtcext[i] = crtcexti(i);
  218. mga->devctrl = pcicfgr32(pci, Devctrl);
  219. mga->option = pcicfgr32(pci, Option);
  220. for(i = 0; i < 64; i++)
  221. mga->tvp[i] = _tvp3026xi(vga, ctlr, i);
  222. for(i = 0; i < 3; i++){
  223. _tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
  224. mga->pclk[i] = _tvp3026xi(vga, ctlr, 0x2D);
  225. }
  226. for(i = 0; i < 3; i++){
  227. _tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
  228. mga->mclk[i] = _tvp3026xi(vga, ctlr, 0x2E);
  229. }
  230. for(i = 0; i < 3; i++){
  231. _tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
  232. mga->lclk[i] = _tvp3026xi(vga, ctlr, 0x2F);
  233. }
  234. /* find out how much memory is here, some multiple of 2Meg */
  235. crtcexto(3, mga->crtcext[3] | 0x80); /* mga mode */
  236. p = (uchar*)mga->membase2;
  237. n = (mga->devid==MGA2064? 4 : 8);
  238. for(i = 0; i < n; i++) {
  239. k = (2*i+1)*Meg;
  240. p[k] = 0;
  241. p[k] = i+1;
  242. *((uchar*)(mga->membase1+CACHEFLUSH)) = 0;
  243. x[i] = p[k];
  244. trace("x[%d]=%d\n", i, x[i]);
  245. }
  246. for(i = 1; i < n; i++)
  247. if(x[i] != i+1)
  248. break;
  249. vga->vmz = 2*i*Meg;
  250. trace("probe found %d megabytes\n", 2*i);
  251. crtcexto(3, mga->crtcext[3]); /* restore mga mode */
  252. ctlr->flag |= Fsnarf;
  253. }
  254. static void
  255. options(Vga* vga, Ctlr* ctlr)
  256. {
  257. if(vga->virtx & 127)
  258. vga->virtx = (vga->virtx+127)&~127;
  259. ctlr->flag |= Foptions;
  260. }
  261. static void
  262. init(Vga* vga, Ctlr* ctlr)
  263. {
  264. Mode *mode;
  265. Ctlr *c;
  266. Mga *mga;
  267. int scale, offset, pixbuswidth;
  268. mga = vga->private;
  269. mode = vga->mode;
  270. ctlr->flag |= Ulinear;
  271. pixbuswidth = (vga->vmz == 2*Meg) ? 32 : 64;
  272. trace("pixbuswidth=%d\n", pixbuswidth);
  273. if(vga->mode->z > 8)
  274. error("depth %d not supported\n", vga->mode->z);
  275. if(vga->f[0] == 0)
  276. vga->f[0] = vga->mode->frequency;
  277. /* supposed to let tvp reg 1D control sync polarity */
  278. vga->misc |= 0xC8;
  279. /*
  280. * In power graphics mode, supposed to use
  281. * hblkend = htotal+4
  282. * hblkstr = hdispend
  283. */
  284. if((vga->crt[0x00] & 0x0F) == 0x0F) {
  285. vga->crt[0x00]++;
  286. mode->ht += 8;
  287. }
  288. vga->crt[0x02] = vga->crt[0x01];
  289. vga->crt[0x03] = (((mode->ht>>3)-1) & 0x1F) | 0x80;
  290. vga->crt[0x05] = ((((mode->ht>>3)-1) & 0x20) << 2)
  291. | ((mode->ehs>>3) & 0x1F);
  292. offset = (vga->virtx*mode->z) >> ((pixbuswidth==32)? 6 : 7);
  293. vga->crt[0x13] = offset;
  294. vga->crt[0x14] = 0;
  295. vga->crt[0x17] = 0xE3;
  296. mga->crtcext[0] = (offset & 0x300) >> 4;
  297. mga->crtcext[1] = ((((mode->ht>>3)-5) & 0x100) >> 8)
  298. | ((((mode->x>>3)-1) & 0x100) >> 7)
  299. | (((mode->shs>>3) & 0x100) >> 6) /* why not (shs>>3)-1 ? */
  300. | (((mode->ht>>3)-1) & 0x40);
  301. mga->crtcext[2] = (((mode->vt-2) & 0xC00) >> 10)
  302. | (((mode->y-1) & 0x400) >> 8)
  303. | ((mode->vrs & 0xC00) >> 7)
  304. | ((mode->vrs & 0xC00) >> 5);
  305. scale = mode->z == 8 ? 1 : (mode->z == 16? 2 : 4);
  306. if(pixbuswidth == 32)
  307. scale *= 2;
  308. scale--;
  309. mga->crtcext[3] = scale | 0x80;
  310. if(vga->vmz >= 8*Meg)
  311. mga->crtcext[3] |= 0x10;
  312. else if(vga->vmz == 2*Meg)
  313. mga->crtcext[3] |= 0x08;
  314. mga->crtcext[4] = 0;
  315. mga->crtcext[5] = 0;
  316. mga->tvp[0x0F] = (mode->z == 8) ? 0x06 : 0x07;
  317. mga->tvp[0x18] = (mode->z == 8) ? 0x80 :
  318. (mode->z == 16) ? 0x05 : 0x06;
  319. mga->tvp[0x19] = (mode->z == 8) ? 0x4C :
  320. (mode->z == 16) ? 0x54 : 0x5C;
  321. if(pixbuswidth == 32)
  322. mga->tvp[0x19]--;
  323. mga->tvp[0x1A] = (mode->z == 8) ? 0x25 :
  324. (mode->z == 16) ? 0x15 : 0x05;
  325. mga->tvp[0x1C] = 0;
  326. mga->tvp[0x1D] = (mode->y < 768) ? 0x00 : 0x03;
  327. mga->tvp[0x1E] = (mode->z == 8) ? 0x04 : 0x24; /* six bit mode */
  328. mga->tvp[0x2A] = 0;
  329. mga->tvp[0x2B] = 0x1E;
  330. mga->tvp[0x30] = 0xFF;
  331. mga->tvp[0x31] = 0xFF;
  332. mga->tvp[0x32] = 0xFF;
  333. mga->tvp[0x33] = 0xFF;
  334. mga->tvp[0x34] = 0xFF;
  335. mga->tvp[0x35] = 0xFF;
  336. mga->tvp[0x36] = 0xFF;
  337. mga->tvp[0x37] = 0xFF;
  338. mga->tvp[0x38] = 0;
  339. mga->tvp[0x39] = 0;
  340. mga->tvp[0x3A] = 0;
  341. mga->tvp[0x06] = 0;
  342. // From: "Bruce G. Stewart" <bruce.g.stewart@worldnet.att.net>
  343. // 05-Jul-00 - Fix vertical blanking setup
  344. // This should probably be corrected in vga.c too.
  345. {
  346. // Start vertical blanking after the last displayed line
  347. // End vertical blanking after the total line count
  348. int svb = mode->y;
  349. int evb = mode->vt;
  350. // A field is 1/2 of the lines in interlaced mode
  351. if(mode->interlace == 'v'){
  352. svb /= 2;
  353. evb /= 2;
  354. }
  355. --svb;
  356. --evb; // line counter counts from 0
  357. vga->crt[0x15] = svb;
  358. vga->crt[0x07] = (vga->crt[0x07] & ~0x08) | ((svb & 0x100)>>5);
  359. vga->crt[0x09] = (vga->crt[0x09] & ~0x20) | ((svb & 0x200)>>4);
  360. // MGA specific: bits 10 and 11
  361. mga->crtcext[0x02] &= ~0x18;
  362. mga->crtcext[0x02] |= ((svb & 0xC00)>>7);
  363. vga->crt[0x16] = evb;
  364. }
  365. clockcalc(vga, ctlr, mode->z);
  366. mga->option = mga->option & ~0x3000;
  367. if(vga->vmz > 2*Meg)
  368. mga->option |= 0x1000;
  369. /* disable vga load (want to do fields in different order) */
  370. for(c = vga->link; c; c = c->link)
  371. if(c->name == "vga")
  372. c->load = nil;
  373. ctlr->flag |= Finit;
  374. }
  375. static void
  376. load(Vga* vga, Ctlr* ctlr)
  377. {
  378. int i;
  379. Mga *mga;
  380. Pcidev* pci;
  381. mga = vga->private;
  382. pci = mga->pci;
  383. trace("loading crtcext0-5\n");
  384. /* turn on mga mode, set other crt high bits */
  385. for(i = 0; i < 6; i++)
  386. crtcexto(i, mga->crtcext[i]);
  387. trace("setting memory mode\n");
  388. /* set memory mode */
  389. pcicfgw32(pci, Option, mga->option);
  390. /* clocksource: pixel clock PLL */
  391. _tvp3026xo(vga, ctlr, 0x1A, mga->tvp[0x1A]);
  392. /* disable pclk and lclk */
  393. _tvp3026xo(vga, ctlr, 0x2C, 0x2A);
  394. _tvp3026xo(vga, ctlr, 0x2F, 0);
  395. _tvp3026xo(vga, ctlr, 0x2D, 0);
  396. trace("loading vga registers\n");
  397. /* vga misc, seq, and registers */
  398. vgao(MiscW, vga->misc);
  399. for(i = 2; i < 0x05; i++)
  400. vgaxo(Seqx, i, vga->sequencer[i]);
  401. vgaxo(Crtx, 0x11, vga->crt[0x11] & ~0x80);
  402. for(i = 0; i < 0x19; i++)
  403. vgaxo(Crtx, i, vga->crt[i]);
  404. /* apparently AGP needs this to restore start address */
  405. crtcexto(0, mga->crtcext[0]);
  406. trace("programming pclk\n");
  407. /* set up pclk */
  408. _tvp3026xo(vga, ctlr, 0x2C, 0);
  409. for(i = 0; i < 3; i++)
  410. _tvp3026xo(vga, ctlr, 0x2D, mga->pclk[i]);
  411. while(!(_tvp3026xi(vga, ctlr, 0x2D) & 0x40))
  412. ;
  413. trace("programming lclk\n");
  414. /* set up lclk */
  415. _tvp3026xo(vga, ctlr, 0x39, mga->tvp[0x39]);
  416. _tvp3026xo(vga, ctlr, 0x2C, 0);
  417. for(i = 0; i < 3; i++)
  418. _tvp3026xo(vga, ctlr, 0x2F, mga->lclk[i]);
  419. while(!(_tvp3026xi(vga, ctlr, 0x2F) & 0x40))
  420. ;
  421. trace("loading tvp registers\n");
  422. /* tvp registers, order matters */
  423. _tvp3026xo(vga, ctlr, 0x0F, mga->tvp[0x0F]);
  424. _tvp3026xo(vga, ctlr, 0x18, mga->tvp[0x18]);
  425. _tvp3026xo(vga, ctlr, 0x19, mga->tvp[0x19]);
  426. _tvp3026xo(vga, ctlr, 0x1A, mga->tvp[0x1A]);
  427. _tvp3026xo(vga, ctlr, 0x1C, mga->tvp[0x1C]);
  428. _tvp3026xo(vga, ctlr, 0x1D, mga->tvp[0x1D]);
  429. _tvp3026xo(vga, ctlr, 0x1E, mga->tvp[0x1E]);
  430. _tvp3026xo(vga, ctlr, 0x2A, mga->tvp[0x2A]);
  431. _tvp3026xo(vga, ctlr, 0x2B, mga->tvp[0x2B]);
  432. _tvp3026xo(vga, ctlr, 0x30, mga->tvp[0x30]);
  433. _tvp3026xo(vga, ctlr, 0x31, mga->tvp[0x31]);
  434. _tvp3026xo(vga, ctlr, 0x32, mga->tvp[0x32]);
  435. _tvp3026xo(vga, ctlr, 0x33, mga->tvp[0x33]);
  436. _tvp3026xo(vga, ctlr, 0x34, mga->tvp[0x34]);
  437. _tvp3026xo(vga, ctlr, 0x35, mga->tvp[0x35]);
  438. _tvp3026xo(vga, ctlr, 0x36, mga->tvp[0x36]);
  439. _tvp3026xo(vga, ctlr, 0x37, mga->tvp[0x37]);
  440. _tvp3026xo(vga, ctlr, 0x38, mga->tvp[0x38]);
  441. _tvp3026xo(vga, ctlr, 0x39, mga->tvp[0x39]);
  442. _tvp3026xo(vga, ctlr, 0x3A, mga->tvp[0x3A]);
  443. _tvp3026xo(vga, ctlr, 0x06, mga->tvp[0x06]);
  444. trace("done mga load\n");
  445. ctlr->flag |= Fload;
  446. }
  447. static void
  448. dump(Vga* vga, Ctlr* ctlr)
  449. {
  450. int i;
  451. char *name;
  452. Mga *mga;
  453. name = ctlr->name;
  454. mga = vga->private;
  455. printitem(name, "Devctrl");
  456. printreg(mga->devctrl);
  457. printitem(name, "Option");
  458. printreg(mga->option);
  459. printitem(name, "Crtcext");
  460. for(i = 0; i < 0x06; i++)
  461. printreg(mga->crtcext[i]);
  462. printitem(name, "TVP");
  463. for(i = 0; i < 64; i++)
  464. printreg(mga->tvp[i]);
  465. printitem(name, "PCLK");
  466. for(i = 0; i < 3; i++)
  467. printreg(mga->pclk[i]);
  468. printitem(name, "MCLK");
  469. for(i = 0; i < 3; i++)
  470. printreg(mga->mclk[i]);
  471. printitem(name, "LCLK");
  472. for(i = 0; i < 3; i++)
  473. printreg(mga->lclk[i]);
  474. }
  475. Ctlr mga2164w = {
  476. "mga2164w", /* name */
  477. snarf, /* snarf */
  478. options, /* options */
  479. init, /* init */
  480. load, /* load */
  481. dump, /* dump */
  482. };
  483. Ctlr mga2164whwgc = {
  484. "mga2164whwgc", /* name */
  485. 0, /* snarf */
  486. 0, /* options */
  487. 0, /* init */
  488. 0, /* load */
  489. dump, /* dump */
  490. };