3dfx.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. /*
  7. * 3Dfx.
  8. */
  9. enum {
  10. dramInit0 = 0x018/4,
  11. dramInit1 = 0x01C/4,
  12. vgaInit0 = 0x028/4,
  13. pllCtrl0 = 0x040/4,
  14. pllCtrl1 = 0x044/4,
  15. pllCtrl2 = 0x048/4,
  16. dacMode = 0x04C/4,
  17. vidProcCfg = 0x05C/4,
  18. vidScreenSize = 0x098/4,
  19. vidDesktopOverlayStride = 0x0E8/4,
  20. Nior = 0x100/4,
  21. };
  22. typedef struct Tdfx {
  23. ulong io;
  24. Pcidev* pci;
  25. ulong r[Nior];
  26. } Tdfx;
  27. static ulong
  28. io32r(Tdfx* tdfx, int r)
  29. {
  30. return inportl(tdfx->io+(r*4));
  31. }
  32. static void
  33. io32w(Tdfx* tdfx, int r, ulong l)
  34. {
  35. outportl(tdfx->io+(r*4), l);
  36. }
  37. static void
  38. snarf(Vga* vga, Ctlr* ctlr)
  39. {
  40. int i;
  41. ulong v;
  42. Tdfx *tdfx;
  43. if(vga->private == nil){
  44. tdfx = alloc(sizeof(Tdfx));
  45. tdfx->pci = pcimatch(0, 0x121A, 0);
  46. if(tdfx->pci == nil)
  47. error("%s: not found\n", ctlr->name);
  48. switch(tdfx->pci->did){
  49. default:
  50. error("%s: unknown chip - DID %4.4uX\n",
  51. ctlr->name, tdfx->pci->did);
  52. break;
  53. case 0x0003: /* Banshee */
  54. vga->f[1] = 270000000;
  55. break;
  56. case 0x0005: /* Avenger (a.k.a. Voodoo3) */
  57. vga->f[1] = 300000000;
  58. break;
  59. case 0x0009: /* Voodoo5 */
  60. vga->f[1] = 350000000;
  61. break;
  62. }
  63. /*
  64. * Frequency output of PLL's is given by
  65. * fout = RefFreq*(n+2)/((m+2)*2^p)
  66. * where there are 6 bits for m, 8 bits for n
  67. * and 2 bits for p (k).
  68. */
  69. vga->m[1] = 64;
  70. vga->n[1] = 256;
  71. vga->p[1] = 4;
  72. if((v = (tdfx->pci->mem[2].bar & ~0x3)) == 0)
  73. error("%s: I/O not mapped\n", ctlr->name);
  74. tdfx->io = v;
  75. vga->private = tdfx;
  76. }
  77. tdfx = vga->private;
  78. vga->crt[0x1A] = vgaxi(Crtx, 0x1A);
  79. vga->crt[0x1B] = vgaxi(Crtx, 0x1B);
  80. for(i = 0; i < Nior; i++)
  81. tdfx->r[i] = io32r(tdfx, i);
  82. /*
  83. * If SDRAM then there's 16MB memory else it's SGRAM
  84. * and can count it based on the power-on straps -
  85. * chip size can be 8Mb or 16Mb, and there can be 4 or
  86. * 8 of them.
  87. */
  88. vga->vma = tdfx->pci->mem[1].size;
  89. if(tdfx->r[dramInit1] & 0x40000000)
  90. vga->vmz = 16*1024*1024;
  91. else{
  92. if(tdfx->r[dramInit0] & 0x08000000)
  93. i = 16*1024*1024/8;
  94. else
  95. i = 8*1024*1024/8;
  96. if(tdfx->r[dramInit0] & 0x04000000)
  97. i *= 8;
  98. else
  99. i *= 4;
  100. vga->vmz = i;
  101. }
  102. ctlr->flag |= Fsnarf;
  103. }
  104. static void
  105. options(Vga*, Ctlr* ctlr)
  106. {
  107. ctlr->flag |= Hlinear|Hclk2|Foptions;
  108. }
  109. static void
  110. tdfxclock(Vga* vga, Ctlr*)
  111. {
  112. int d, dmin;
  113. uint f, m, n, p;
  114. dmin = vga->f[0];
  115. for(m = 1; m < vga->m[1]; m++){
  116. for(n = 1; n < vga->n[1]; n++){
  117. f = (RefFreq*(n+2))/(m+2);
  118. for(p = 0; p < vga->p[1]; p++){
  119. d = vga->f[0] - (f/(1<<p));
  120. if(d < 0)
  121. d = -d;
  122. if(d >= dmin)
  123. continue;
  124. dmin = d;
  125. vga->m[0] = m;
  126. vga->n[0] = n;
  127. vga->p[0] = p;
  128. }
  129. }
  130. }
  131. }
  132. static void
  133. init(Vga* vga, Ctlr* ctlr)
  134. {
  135. int x;
  136. Mode *mode;
  137. Tdfx *tdfx;
  138. mode = vga->mode;
  139. tdfx = vga->private;
  140. if(vga->linear && (ctlr->flag & Hlinear))
  141. ctlr->flag |= Ulinear;
  142. /*
  143. * Clock bits. If the desired video clock is
  144. * one of the two standard VGA clocks or 50MHz it can just be
  145. * set using bits <3:2> of vga->misc, otherwise we
  146. * need to programme the PLL.
  147. */
  148. if(vga->f[0] == 0)
  149. vga->f[0] = mode->frequency;
  150. vga->misc &= ~0x0C;
  151. if(vga->f[0] == VgaFreq0){
  152. /* nothing to do */;
  153. }
  154. else if(vga->f[0] == VgaFreq1)
  155. vga->misc |= 0x04;
  156. else if(vga->f[0] == 50000000)
  157. vga->misc |= 0x08;
  158. else{
  159. if(vga->f[0] > vga->f[1])
  160. error("%s: invalid pclk - %lud\n",
  161. ctlr->name, vga->f[0]);
  162. if(vga->f[0] > 135000000 && (ctlr->flag & Hclk2)){
  163. if(mode->x%16)
  164. error("%s: f > 135MHz requires (x%%16) == 0\n",
  165. ctlr->name);
  166. ctlr->flag |= Uclk2;
  167. }
  168. tdfxclock(vga, ctlr);
  169. tdfx->r[pllCtrl0] = (vga->n[0]<<8)|(vga->m[0]<<2)|vga->p[0];
  170. vga->misc |= 0x0C;
  171. }
  172. /*
  173. * Pixel format and memory stride.
  174. */
  175. tdfx->r[vidScreenSize] = (mode->y<<12)|mode->x;
  176. tdfx->r[vidProcCfg] = 0x00000081;
  177. switch(mode->z){
  178. default:
  179. error("%s: %d-bit mode not supported\n", ctlr->name, mode->z);
  180. break;
  181. case 8:
  182. tdfx->r[vidDesktopOverlayStride] = mode->x;
  183. break;
  184. case 16:
  185. tdfx->r[vidDesktopOverlayStride] = mode->x*2;
  186. tdfx->r[vidProcCfg] |= 0x00040400;
  187. break;
  188. case 32:
  189. tdfx->r[vidDesktopOverlayStride] = mode->x*4;
  190. tdfx->r[vidProcCfg] |= 0x000C0400;
  191. break;
  192. }
  193. tdfx->r[vgaInit0] = 0x140;
  194. /*
  195. * Adjust horizontal timing if doing two screen pixels per clock.
  196. */
  197. tdfx->r[dacMode] = 0;
  198. if(ctlr->flag & Uclk2){
  199. vga->crt[0x00] = ((mode->ht/2)>>3)-5;
  200. vga->crt[0x01] = ((mode->x/2)>>3)-1;
  201. vga->crt[0x02] = ((mode->shb/2)>>3)-1;
  202. x = (mode->ehb/2)>>3;
  203. vga->crt[0x03] = 0x80|(x & 0x1F);
  204. vga->crt[0x04] = (mode->shs/2)>>3;
  205. vga->crt[0x05] = ((mode->ehs/2)>>3) & 0x1F;
  206. if(x & 0x20)
  207. vga->crt[0x05] |= 0x80;
  208. tdfx->r[dacMode] |= 0x01;
  209. tdfx->r[vidProcCfg] |= 0x04000000;
  210. }
  211. /*
  212. * Overflow.
  213. */
  214. vga->crt[0x1A] = 0x00;
  215. if(vga->crt[0x00] & 0x100)
  216. vga->crt[0x1A] |= 0x01;
  217. if(vga->crt[0x01] & 0x100)
  218. vga->crt[0x1A] |= 0x04;
  219. if(vga->crt[0x03] & 0x100)
  220. vga->crt[0x1A] |= 0x10;
  221. x = mode->ehb;
  222. if(ctlr->flag & Uclk2)
  223. x /= 2;
  224. if((x>>3) & 0x40)
  225. vga->crt[0x1A] |= 0x20;
  226. if(vga->crt[0x04] & 0x100)
  227. vga->crt[0x1A] |= 0x40;
  228. x = mode->ehs;
  229. if(ctlr->flag & Uclk2)
  230. x /= 2;
  231. if((x>>3) & 0x20)
  232. vga->crt[0x1A] |= 0x80;
  233. vga->crt[0x1B] = 0x00;
  234. if(vga->crt[0x06] & 0x400)
  235. vga->crt[0x1B] |= 0x01;
  236. if(vga->crt[0x12] & 0x400)
  237. vga->crt[0x1B] |= 0x04;
  238. if(vga->crt[0x15] & 0x400)
  239. vga->crt[0x1B] |= 0x10;
  240. if(vga->crt[0x10] & 0x400)
  241. vga->crt[0x1B] |= 0x40;
  242. vga->attribute[0x11] = Pblack;
  243. ctlr->flag |= Finit;
  244. }
  245. static void
  246. load(Vga* vga, Ctlr* ctlr)
  247. {
  248. Tdfx *tdfx;
  249. vgaxo(Crtx, 0x1A, vga->crt[0x1A]);
  250. vgaxo(Crtx, 0x1B, vga->crt[0x1B]);
  251. tdfx = vga->private;
  252. io32w(tdfx, dacMode, tdfx->r[dacMode]);
  253. io32w(tdfx, vidScreenSize, tdfx->r[vidScreenSize]);
  254. io32w(tdfx, vidDesktopOverlayStride, tdfx->r[vidDesktopOverlayStride]);
  255. io32w(tdfx, vidProcCfg, tdfx->r[vidProcCfg]);
  256. io32w(tdfx, vgaInit0, tdfx->r[vgaInit0]);
  257. if((vga->misc & 0x0C) == 0x0C)
  258. io32w(tdfx, pllCtrl0, tdfx->r[pllCtrl0]);
  259. ctlr->flag |= Fload;
  260. }
  261. static uint
  262. pllctrl(Tdfx* tdfx, int pll)
  263. {
  264. uint k, m, n, r;
  265. r = tdfx->r[pllCtrl0+pll];
  266. k = r & 0x03;
  267. m = (r>>2) & 0x3F;
  268. n = (r>>8) & 0xFF;
  269. return (RefFreq*(n+2))/((m+2)*(1<<k));
  270. }
  271. static void
  272. dump(Vga* vga, Ctlr* ctlr)
  273. {
  274. int i;
  275. Tdfx *tdfx;
  276. if((tdfx = vga->private) == nil)
  277. return;
  278. printitem(ctlr->name, "Crt1A");
  279. printreg(vga->crt[0x1A]);
  280. printreg(vga->crt[0x1B]);
  281. Bprint(&stdout, "\n");
  282. for(i = 0; i < Nior; i++)
  283. Bprint(&stdout, "%s %2.2uX\t%.8luX\n",
  284. ctlr->name, i*4, tdfx->r[i]);
  285. printitem(ctlr->name, "pllCtrl");
  286. Bprint(&stdout, "%9ud %8ud\n", pllctrl(tdfx, 0), pllctrl(tdfx, 1));
  287. }
  288. Ctlr tdfx = {
  289. "3dfx", /* name */
  290. snarf, /* snarf */
  291. options, /* options */
  292. init, /* init */
  293. load, /* load */
  294. dump, /* dump */
  295. };
  296. Ctlr tdfxhwgc = {
  297. "3dfxhwgc", /* name */
  298. 0, /* snarf */
  299. 0, /* options */
  300. 0, /* init */
  301. 0, /* load */
  302. 0, /* dump */
  303. };