trio64.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. /*
  7. * S3 Trio64.
  8. */
  9. static void
  10. snarf(Vga* vga, Ctlr* ctlr)
  11. {
  12. int i;
  13. /*
  14. * The Trio has some extra sequencer registers which
  15. * need to be unlocked for access.
  16. */
  17. vgaxo(Seqx, 0x08, 0x06);
  18. for(i = 0x08; i < 0x19; i++)
  19. vga->sequencer[i] = vgaxi(Seqx, i);
  20. vga->crt[0x2D] = vgaxi(Crtx, 0x2D);
  21. vga->crt[0x2E] = vgaxi(Crtx, 0x2E);
  22. vga->crt[0x2F] = vgaxi(Crtx, 0x2F);
  23. s3generic.snarf(vga, ctlr);
  24. ctlr->flag |= Fsnarf;
  25. }
  26. static void
  27. options(Vga*, Ctlr* ctlr)
  28. {
  29. ctlr->flag |= Hlinear|Hpclk2x8|Henhanced|Foptions;
  30. }
  31. void
  32. trio64clock(Vga* vga, Ctlr* ctlr)
  33. {
  34. int d;
  35. ulong f, fmax, fmin, n, m, r;
  36. double trouble;
  37. /*
  38. * The max value of R, M, N, and the speed rating of the part vary
  39. * between parts and are passed to this routine in r[1] and f[1].
  40. * R F
  41. * Trio64 3 135000000
  42. * ViRGE 3 135000000
  43. * ViRGE/[DG]X 4 170000000
  44. * ViRGE/GX2 4 170000000
  45. * ViRGE/VX 4 220000000
  46. */
  47. /*
  48. * The PLL frequency is defined by the following equation:
  49. * (M+2)
  50. * Fout = ------------- x Fref
  51. * (N+2) x 2**R
  52. * where M, N and R have the following contraints:
  53. * 1) (M+2) x Fref
  54. * vga->f[1] <= ------------ <= vga->f[1]*2
  55. * (N+2)
  56. * 2) 1 <= M <= vga->m[1] (usually 127)
  57. * 3) 1 <= N <= vga->n[1] (usually 31)
  58. * 4) 0 <= R <= vga->r[1]
  59. *
  60. * First determine R:
  61. * vga->f[1] < 2**R x Fout <= vga->f[1]*2
  62. */
  63. for(r = 0; r <= vga->r[1]; r++){
  64. f = vga->f[0]*(1<<r);
  65. if(vga->f[1] < f && f <= vga->f[1]*2)
  66. vga->r[0] = r;
  67. }
  68. if(vga->r[0] > vga->r[1])
  69. error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
  70. /*
  71. * Now find the closest match for M and N.
  72. */
  73. vga->d[0] = vga->f[0]+1;
  74. for(n = 1; n <= vga->n[1]; n++){
  75. trouble = vga->f[0]*(n+2)*(1<<vga->r[0]);
  76. trouble /= RefFreq;
  77. m = (trouble+0.5) - 2;
  78. if(m > vga->m[1])
  79. continue;
  80. trouble = (m+2)*RefFreq;
  81. trouble /= (n+2)*(1<<vga->r[0]);
  82. f = trouble+0.5;
  83. d = vga->f[0] - f;
  84. if(d < 0)
  85. d = -d;
  86. if(d <= vga->d[0]){
  87. vga->m[0] = m;
  88. vga->n[0] = n;
  89. vga->d[0] = d;
  90. }
  91. }
  92. trouble = vga->f[0]*1.005;
  93. fmax = trouble;
  94. trouble = vga->f[0]*0.995;
  95. fmin = trouble;
  96. trouble = (vga->m[0]+2)*RefFreq;
  97. trouble /= (vga->n[0]+2)*(1<<vga->r[0]);
  98. f = trouble+0.5;
  99. if(fmin >= f || f >= fmax)
  100. error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
  101. }
  102. static void
  103. init(Vga* vga, Ctlr* ctlr)
  104. {
  105. ulong pclk, x;
  106. s3generic.init(vga, ctlr);
  107. /*
  108. * Clock bits. If the desired video clock is
  109. * one of the two standard VGA clocks it can just be
  110. * set using bits <3:2> of vga->misc, otherwise we
  111. * need to programme the DCLK PLL.
  112. */
  113. if(vga->mode->z > 8)
  114. error("depth %d not supported\n", vga->mode->z);
  115. if(vga->f[0] == 0)
  116. vga->f[0] = vga->mode->frequency;
  117. vga->misc &= ~0x0C;
  118. if(vga->f[0] == VgaFreq0){
  119. /* nothing to do */;
  120. }
  121. else if(vga->f[0] == VgaFreq1)
  122. vga->misc |= 0x04;
  123. else{
  124. /*
  125. * Part comes in -135MHz speed grade. In 8-bit mode
  126. * the maximum DCLK is 80MHz. In 2x8-bit mode the maximum
  127. * DCLK is 135MHz using the internal clock doubler.
  128. */
  129. if((ctlr->flag & Hpclk2x8) && vga->mode->z == 8){
  130. pclk = 135000000;
  131. if(vga->f[0] > 80000000)
  132. ctlr->flag |= Upclk2x8;
  133. }
  134. else
  135. pclk = 80000000;
  136. if(vga->f[0] > pclk)
  137. error("%s: invalid pclk - %lud\n",
  138. ctlr->name, vga->f[0]);
  139. vga->f[1] = 135000000;
  140. vga->r[1] = 3;
  141. vga->n[1] = 31;
  142. vga->m[1] = 127;
  143. trio64clock(vga, ctlr);
  144. vga->sequencer[0x12] = (vga->r[0]<<5)|vga->n[0];
  145. vga->sequencer[0x13] = vga->m[0];
  146. vga->misc |= 0x0C;
  147. }
  148. /*
  149. * Internal clock generator.
  150. */
  151. vga->sequencer[0x15] &= ~0x31;
  152. vga->sequencer[0x15] |= 0x02;
  153. vga->sequencer[0x18] &= ~0x80;
  154. vga->crt[0x67] &= ~0xF2;
  155. if(ctlr->flag & Upclk2x8){
  156. vga->sequencer[0x15] |= 0x10;
  157. vga->sequencer[0x18] |= 0x80;
  158. /*
  159. * There's a little strip of the border
  160. * appears on the left in resolutions
  161. * 1280 and above if the 0x02 bit isn't
  162. * set (when it appears on the right...).
  163. */
  164. vga->crt[0x67] |= 0x10;
  165. }
  166. /*
  167. * VLB address latch delay.
  168. */
  169. if((vga->crt[0x36] & 0x03) == 0x01)
  170. vga->crt[0x58] &= ~0x08;
  171. /*
  172. * Start display FIFO fetch.
  173. */
  174. x = vga->crt[0]-5;
  175. vga->crt[0x3B] = x;
  176. if(x & 0x100)
  177. vga->crt[0x5D] |= 0x40;
  178. /*
  179. * Display memory access control.
  180. * Calculation of the M-parameter (Crt54) is
  181. * memory-system and dot-clock dependent, the
  182. * values below are guesses from dumping
  183. * registers.
  184. */
  185. vga->crt[0x60] = 0xFF;
  186. if(vga->mode->x <= 800)
  187. vga->crt[0x54] = 0xE8;
  188. else if(vga->mode->x <= 1024)
  189. vga->crt[0x54] = 0xA8;
  190. else
  191. vga->crt[0x54] = 0x00/*0x48*/;
  192. ctlr->flag |= Finit;
  193. }
  194. static void
  195. load(Vga* vga, Ctlr* ctlr)
  196. {
  197. ushort advfunc;
  198. s3generic.load(vga, ctlr);
  199. vgaxo(Crtx, 0x60, vga->crt[0x60]);
  200. vgaxo(Crtx, 0x67, vga->crt[0x67]);
  201. /*
  202. * Load the PLL registers if necessary.
  203. * Not sure if the variable-delay method of setting the
  204. * PLL will work without a write here to vga->misc,
  205. * so use the immediate-load method by toggling bit 5
  206. * of Seq15 if necessary.
  207. */
  208. vgaxo(Seqx, 0x12, vga->sequencer[0x12]);
  209. vgaxo(Seqx, 0x13, vga->sequencer[0x13]);
  210. if((vga->misc & 0x0C) == 0x0C)
  211. vgaxo(Seqx, 0x15, vga->sequencer[0x15]|0x20);
  212. vgaxo(Seqx, 0x15, vga->sequencer[0x15]);
  213. vgaxo(Seqx, 0x18, vga->sequencer[0x18]);
  214. advfunc = 0x0000;
  215. if(ctlr->flag & Uenhanced)
  216. advfunc = 0x0001;
  217. outportw(0x4AE8, advfunc);
  218. }
  219. static void
  220. dump(Vga* vga, Ctlr* ctlr)
  221. {
  222. int i;
  223. ulong dclk, m, n, r;
  224. s3generic.dump(vga, ctlr);
  225. printitem(ctlr->name, "Seq08");
  226. for(i = 0x08; i < 0x19; i++)
  227. printreg(vga->sequencer[i]);
  228. printitem(ctlr->name, "Crt2D");
  229. printreg(vga->crt[0x2D]);
  230. printreg(vga->crt[0x2E]);
  231. printreg(vga->crt[0x2F]);
  232. n = vga->sequencer[0x12] & 0x1F;
  233. r = (vga->sequencer[0x12]>>5) & 0x03;
  234. m = vga->sequencer[0x13] & 0x7F;
  235. dclk = (m+2)*RefFreq;
  236. dclk /= (n+2)*(1<<r);
  237. printitem(ctlr->name, "dclk m n r");
  238. Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n", dclk, m, n, r);
  239. }
  240. Ctlr trio64 = {
  241. "trio64", /* name */
  242. snarf, /* snarf */
  243. options, /* options */
  244. init, /* init */
  245. load, /* load */
  246. dump, /* dump */
  247. };