s3clock.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. /*
  7. * Clocks which require fiddling with the S3 registers
  8. * in order to be loaded.
  9. */
  10. static void
  11. setcrt42(Vga* vga, Ctlr* ctlr, uchar index)
  12. {
  13. trace("%s->clock->setcrt42\n", ctlr->name);
  14. vgao(MiscW, vga->misc & ~0x0C);
  15. outportb(Crtx+1, 0x00);
  16. vga->crt[0x42] = (vga->crt[0x42] & 0xF0)|index;
  17. vgao(MiscW, vga->misc);
  18. vgaxo(Crtx, 0x42, vga->crt[0x42]);
  19. }
  20. static void
  21. icd2061aload(Vga* vga, Ctlr* ctlr)
  22. {
  23. ulong sdata;
  24. int i;
  25. uchar crt42;
  26. trace("%s->clock->icd2061aload\n", ctlr->name);
  27. /*
  28. * The serial word to be loaded into the icd2061a is
  29. * (2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d
  30. * Always select ICD2061A REG2.
  31. */
  32. sdata = (2<<21)|(vga->i[0]<<17)|((vga->n[0])<<10)|(vga->p[0]<<7)|vga->d[0];
  33. /*
  34. * The display should be already off to enable us to clock the
  35. * serial data word into either MiscW or Crt42.
  36. *
  37. * Set the Misc register to make clock-select-out the contents of
  38. * register Crt42. Must turn the sequencer off when changing bits
  39. * <3:2> of Misc. Also, must set Crt42 to 0 before setting <3:2>
  40. * of Misc due to a hardware glitch.
  41. */
  42. vgao(MiscW, vga->misc & ~0x0C);
  43. crt42 = vgaxi(Crtx, 0x42) & 0xF0;
  44. outportb(Crtx+1, 0x00);
  45. vgaxo(Seqx, 0x00, 0x00);
  46. vgao(MiscW, vga->misc|0x0C);
  47. vgaxo(Seqx, 0x00, 0x03);
  48. /*
  49. * Unlock the ICD2061A. The unlock sequence is at least 5 low-to-high
  50. * transitions of CLK with DATA high, followed by a single low-to-high
  51. * transition of CLK with DATA low.
  52. * Using Crt42, CLK is bit0, DATA is bit 1. If we used MiscW, they'd
  53. * be bits 2 and 3 respectively.
  54. */
  55. outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */
  56. outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */
  57. for(i = 0; i < 5; i++){
  58. outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */
  59. outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */
  60. }
  61. outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */
  62. outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */
  63. /*
  64. * Now write the serial data word, framed by a start-bit and a stop-bit.
  65. * The data is written using a modified Manchester encoding such that a
  66. * data-bit is sampled on the rising edge of CLK and the complement of
  67. * the data-bit is sampled on the previous falling edge of CLK.
  68. */
  69. outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK (start-bit) */
  70. outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */
  71. for(i = 0; i < 24; i++){ /* serial data word */
  72. if(sdata & 0x01){
  73. outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */
  74. outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK (falling edge) */
  75. outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */
  76. outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK (rising edge) */
  77. }
  78. else {
  79. outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */
  80. outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK (falling edge) */
  81. outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */
  82. outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK (rising edge) */
  83. }
  84. sdata >>= 1;
  85. }
  86. outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK (stop-bit) */
  87. outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */
  88. outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */
  89. /*
  90. * We always use REG2 in the ICD2061A.
  91. */
  92. setcrt42(vga, ctlr, 0x02);
  93. }
  94. static void
  95. ch9294load(Vga* vga, Ctlr* ctlr)
  96. {
  97. trace("%s->clock->ch9294load\n", ctlr->name);
  98. setcrt42(vga, ctlr, vga->i[0]);
  99. }
  100. static void
  101. tvp3025load(Vga* vga, Ctlr* ctlr)
  102. {
  103. uchar crt5c, x;
  104. trace("%s->clock->tvp3025load\n", ctlr->name);
  105. /*
  106. * Crt5C bit 5 is RS4.
  107. * Clear it to select TVP3025 registers for
  108. * the calls to tvp302xo().
  109. */
  110. crt5c = vgaxi(Crtx, 0x5C);
  111. vgaxo(Crtx, 0x5C, crt5c & ~0x20);
  112. tvp3020xo(0x2C, 0x00);
  113. tvp3020xo(0x2D, vga->d[0]);
  114. tvp3020xo(0x2D, vga->n[0]);
  115. tvp3020xo(0x2D, 0x08|vga->p[0]);
  116. tvp3020xo(0x2F, 0x01);
  117. tvp3020xo(0x2F, 0x01);
  118. tvp3020xo(0x2F, vga->p[0]);
  119. x = 0x54;
  120. if(vga->ctlr && (vga->ctlr->flag & Uenhanced))
  121. x = 0xC4;
  122. tvp3020xo(0x1E, x);
  123. vgaxo(Crtx, 0x5C, crt5c);
  124. vgao(MiscW, vga->misc);
  125. ctlr->flag |= Fload;
  126. }
  127. static void
  128. tvp3026load(Vga* vga, Ctlr* ctlr)
  129. {
  130. trace("%s->clock->tvp3026load\n", ctlr->name);
  131. if((vga->misc & 0x0C) != 0x0C && vga->mode->z == 1){
  132. tvp3026xo(0x1A, 0x07);
  133. tvp3026xo(0x18, 0x80);
  134. tvp3026xo(0x19, 0x98);
  135. tvp3026xo(0x2C, 0x2A);
  136. tvp3026xo(0x2F, 0x00);
  137. tvp3026xo(0x2D, 0x00);
  138. tvp3026xo(0x39, 0x18);
  139. setcrt42(vga, ctlr, 0);
  140. }
  141. else if(vga->mode->z == 8){
  142. tvp3026xo(0x1A, 0x05);
  143. tvp3026xo(0x18, 0x80);
  144. tvp3026xo(0x19, 0x4C);
  145. tvp3026xo(0x2C, 0x2A);
  146. tvp3026xo(0x2F, 0x00);
  147. tvp3026xo(0x2D, 0x00);
  148. tvp3026xo(0x2C, 0x00);
  149. tvp3026xo(0x2D, 0xC0|vga->n[0]);
  150. tvp3026xo(0x2D, vga->m[0] & 0x3F);
  151. tvp3026xo(0x2D, 0xB0|vga->p[0]);
  152. while(!(tvp3026xi(0x2D) & 0x40))
  153. ;
  154. tvp3026xo(0x39, 0x38|vga->q[1]);
  155. tvp3026xo(0x2C, 0x00);
  156. tvp3026xo(0x2F, 0xC0|vga->n[1]);
  157. tvp3026xo(0x2F, vga->m[1]);
  158. tvp3026xo(0x2F, 0xF0|vga->p[1]);
  159. while(!(tvp3026xi(0x2F) & 0x40))
  160. ;
  161. setcrt42(vga, ctlr, 3);
  162. }
  163. ctlr->flag |= Fload;
  164. }
  165. static struct {
  166. char* name;
  167. void (*load)(Vga*, Ctlr*);
  168. } clocks[] = {
  169. { "icd2061a", icd2061aload, },
  170. { "ch9294", ch9294load, },
  171. { "tvp3025clock", tvp3025load, },
  172. { "tvp3026clock", tvp3026load, },
  173. { 0 },
  174. };
  175. static void
  176. init(Vga* vga, Ctlr* ctlr)
  177. {
  178. char name[Namelen+1], *p;
  179. int i;
  180. if(vga->clock == 0)
  181. return;
  182. /*
  183. * Check we know about it.
  184. */
  185. strncpy(name, vga->clock->name, Namelen);
  186. name[Namelen] = 0;
  187. if(p = strchr(name, '-'))
  188. *p = 0;
  189. for(i = 0; clocks[i].name; i++){
  190. if(strcmp(clocks[i].name, name) == 0)
  191. break;
  192. }
  193. if(clocks[i].name == 0)
  194. error("%s: unknown clock \"%s\"\n", ctlr->name, vga->clock->name);
  195. if(vga->clock->init && (vga->clock->flag & Finit) == 0)
  196. (*vga->clock->init)(vga, vga->clock);
  197. /*
  198. * If we don't already have a desired pclk,
  199. * take it from the mode.
  200. */
  201. if(vga->f[0] == 0)
  202. vga->f[0] = vga->mode->frequency;
  203. if(vga->f[0] != VgaFreq0 && vga->f[0] != VgaFreq1)
  204. vga->misc |= 0x0C;
  205. ctlr->flag |= Finit;
  206. }
  207. static void
  208. load(Vga* vga, Ctlr* ctlr)
  209. {
  210. char name[Namelen+1], *p;
  211. int i;
  212. if(vga->clock == 0 || (vga->clock->flag & Fload))
  213. return;
  214. strncpy(name, vga->clock->name, Namelen);
  215. name[Namelen] = 0;
  216. if(p = strchr(name, '-'))
  217. *p = 0;
  218. for(i = 0; clocks[i].name; i++){
  219. if(strcmp(clocks[i].name, name))
  220. continue;
  221. clocks[i].load(vga, ctlr);
  222. if(strcmp(clocks[i].name, "icd2061a") == 0){
  223. clocks[i].load(vga, ctlr);
  224. clocks[i].load(vga, ctlr);
  225. }
  226. ctlr->flag |= Fload;
  227. return;
  228. }
  229. }
  230. Ctlr s3clock = {
  231. "s3clock", /* name */
  232. 0, /* snarf */
  233. 0, /* options */
  234. init, /* init */
  235. load, /* load */
  236. 0, /* dump */
  237. };