clgd542x.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. /*
  7. * Cirrus Logic True Color VGA Family - CL-GD542X.
  8. * Also works for Alpine VGA Family - CL-GD543X.
  9. * Just the basics. BUGS:
  10. * the added capabilities of the 543X aren't used.
  11. */
  12. typedef struct {
  13. uchar id; /* Id */
  14. ulong vclk; /* Maximum dot clock */
  15. } Gd542x;
  16. static Gd542x family[] = {
  17. { 0x88, 75000000, }, /* CL-GD5420 */
  18. { 0x8C, 80000000, }, /* CL-GD5422 */
  19. { 0x94, 80000000, }, /* CL-GD5424 */
  20. { 0x90, 80000000, }, /* CL-GD5426 */
  21. { 0x98, 80000000, }, /* CL-GD5428 */
  22. { 0x9C, 86000000, }, /* CL-GD5429 */
  23. { 0xA0, 86000000, }, /* CL-GD5430 */
  24. { 0xA8, 86000000, }, /* CL-GD5434 */
  25. { 0xAC, 135000000, }, /* CL-GD5436 */
  26. { 0xB8, 135000000, }, /* CL-GD5446 */
  27. { 0xBC, 135000000, }, /* CL-GD5480 */
  28. { 0x30, 80000000, }, /* CL-GD7543 */
  29. { 0x00, },
  30. };
  31. static Gd542x*
  32. identify(Vga* vga, Ctlr* ctlr)
  33. {
  34. Gd542x *gd542x;
  35. uchar id;
  36. id = vga->crt[0x27] & ~0x03;
  37. for(gd542x = &family[0]; gd542x->id; gd542x++){
  38. if(gd542x->id == id)
  39. return gd542x;
  40. }
  41. error("%s: unknown chip id - 0x%2.2X\n", ctlr->name, vga->crt[0x27]);
  42. return 0;
  43. }
  44. static void
  45. snarf(Vga* vga, Ctlr* ctlr)
  46. {
  47. int i;
  48. Gd542x *gd542x;
  49. /*
  50. * Unlock extended registers.
  51. */
  52. vgaxo(Seqx, 0x06, 0x12);
  53. /*
  54. * Save all the registers, even though we'll only
  55. * change a handful.
  56. */
  57. for(i = 0x06; i < 0x20; i++)
  58. vga->sequencer[i] = vgaxi(Seqx, i);
  59. for(i = 0x09; i < 0x3A; i++)
  60. vga->graphics[i] = vgaxi(Grx, i);
  61. for(i = 0x19; i < 0x1E; i++)
  62. vga->crt[i] = vgaxi(Crtx, i);
  63. vga->crt[0x27] = vgaxi(Crtx, 0x27);
  64. /*
  65. * Hack for Hidden DAC Register. Do 4 dummy reads
  66. * of Pixmask first.
  67. */
  68. for(i = 0; i < 4; i++)
  69. vgai(Pixmask);
  70. vga->crt[0x28] = vgai(Pixmask);
  71. i = 0;
  72. switch(vga->crt[0x27] & ~0x03){
  73. case 0x88: /* CL-GD5420 */
  74. case 0x8C: /* CL-GD5422 */
  75. case 0x94: /* CL-GD5424 */
  76. case 0x80: /* CL-GD5425 */
  77. case 0x90: /* CL-GD5426 */
  78. case 0x98: /* CL-GD5427 */
  79. case 0x9C: /* CL-GD5429 */
  80. /*
  81. * The BIOS leaves the memory size in Seq0A, bits 4 and 3.
  82. * See Technical Reference Manual Appendix E1, Section 1.3.2.
  83. *
  84. * The storage area for the 64x64 cursors is the last 16Kb of
  85. * display memory.
  86. */
  87. i = (vga->sequencer[0x0A]>>3) & 0x03;
  88. break;
  89. case 0xA0: /* CL-GD5430 */
  90. case 0xA8: /* CL-GD5434 */
  91. case 0xAC: /* CL-GD5436 */
  92. case 0xB8: /* CL-GD5446 */
  93. case 0x30: /* CL-GD7543 */
  94. /*
  95. * Attempt to intuit the memory size from the DRAM control
  96. * register. Minimum is 512KB.
  97. * If DRAM bank switching is on then there's double.
  98. */
  99. i = (vga->sequencer[0x0F]>>3) & 0x03;
  100. if(vga->sequencer[0x0F] & 0x80)
  101. i++;
  102. /*
  103. * If it's a PCI card, can do linear.
  104. * Most of the Cirrus chips can do linear addressing with
  105. * all the different buses, but it can get messy. It's easy
  106. * to cut PCI on the CLGD543x chips out of the pack.
  107. */
  108. if(((vga->sequencer[0x17]>>3) & 0x07) == 0x04)
  109. ctlr->flag |= Hlinear;
  110. break;
  111. case 0xBC: /* CL-GD5480 */
  112. i = 2; /* 1024 = 256<<2 */
  113. if((vga->sequencer[0x0F] & 0x18) == 0x18){
  114. i <<= 1; /* 2048 = 256<<3 */
  115. if(vga->sequencer[0x0F] & 0x80)
  116. i <<= 2; /* 2048 = 256<<4 */
  117. }
  118. if(vga->sequencer[0x17] & 0x80)
  119. i <<= 1;
  120. ctlr->flag |= Hlinear;
  121. break;
  122. default: /* uh, ah dunno */
  123. break;
  124. }
  125. if(vga->linear && (ctlr->flag & Hlinear)){
  126. vga->vmz = 16*1024*1024;
  127. vga->vma = 16*1024*1024;
  128. ctlr->flag |= Ulinear;
  129. }
  130. else
  131. vga->vmz = (256<<i)*1024;
  132. gd542x = identify(vga, ctlr);
  133. if(vga->f[1] == 0 || vga->f[1] > gd542x->vclk)
  134. vga->f[1] = gd542x->vclk;
  135. ctlr->flag |= Fsnarf;
  136. }
  137. void
  138. clgd54xxclock(Vga* vga, Ctlr* ctlr)
  139. {
  140. int f;
  141. ulong d, dmin, fmin, n, nmin, p;
  142. trace("%s->init->clgd54xxclock\n", ctlr->name);
  143. /*
  144. * Athough the Technical Reference Manual says only a handful
  145. * of frequencies are tested, it also gives the following formula
  146. * which can be used to generate any frequency within spec.,
  147. * including the tested ones.
  148. *
  149. * Numerator is 7-bits, denominator 5-bits.
  150. * Guess from the Technical Reference Manual that
  151. * The post divisor is 1 for vclk<40MHz.
  152. *
  153. * Look for values of n and d and p that give
  154. * the least error for
  155. * vclk = (RefFreq*n)/(d*(1+p));
  156. *
  157. * There's nothing like brute force and ignorance.
  158. */
  159. fmin = vga->f[0];
  160. nmin = 69;
  161. dmin = 24;
  162. if(vga->f[0] >= 40000000)
  163. p = 0;
  164. else
  165. p = 1;
  166. for(n = 1; n < 128; n++){
  167. for(d = 1; d < 32; d++){
  168. f = vga->f[0] - (RefFreq*n)/(d*(1+p));
  169. if(f < 0)
  170. f = -f;
  171. if(f <= fmin){
  172. fmin = f;
  173. nmin = n;
  174. dmin = d;
  175. }
  176. }
  177. }
  178. vga->f[0] = (RefFreq*nmin)/(dmin*(1+p));
  179. vga->d[0] = dmin;
  180. vga->n[0] = nmin;
  181. vga->p[0] = p;
  182. }
  183. void
  184. init(Vga* vga, Ctlr* ctlr)
  185. {
  186. Mode *mode;
  187. Gd542x *gd542x;
  188. ushort x;
  189. mode = vga->mode;
  190. gd542x = identify(vga, ctlr);
  191. if(vga->f[0] == 0)
  192. vga->f[0] = vga->mode->frequency;
  193. if(vga->f[0] > gd542x->vclk)
  194. error("%s: pclk %lud too high (> %lud)\n",
  195. ctlr->name, vga->f[0], gd542x->vclk);
  196. if(mode->z > 8)
  197. error("%s: depth %d not supported\n", ctlr->name, mode->z);
  198. /*
  199. * VCLK3
  200. */
  201. clgd54xxclock(vga, ctlr);
  202. vga->misc |= 0x0C;
  203. vga->sequencer[0x0E] = vga->n[0];
  204. vga->sequencer[0x1E] = (vga->d[0]<<1)|vga->p[0];
  205. vga->sequencer[0x07] = 0x00;
  206. if(mode->z == 8)
  207. vga->sequencer[0x07] |= 0x01;
  208. if(vga->f[0] >= 42000000)
  209. vga->sequencer[0x0F] |= 0x20;
  210. else
  211. vga->sequencer[0x0F] &= ~0x20;
  212. vga->sequencer[0x16] = (vga->sequencer[0x16] & 0xF0)|0x08;
  213. /*
  214. * Overflow bits.
  215. */
  216. vga->crt[0x1A] = 0x00;
  217. x = mode->ehb>>3;
  218. if(x & 0x40)
  219. vga->crt[0x1A] |= 0x10;
  220. if(x & 0x80)
  221. vga->crt[0x1A] |= 0x20;
  222. if(vga->crt[0x16] & 0x100)
  223. vga->crt[0x1A] |= 0x40;
  224. if(vga->crt[0x16] & 0x200)
  225. vga->crt[0x1A] |= 0x80;
  226. vga->crt[0x1B] = 0x22;
  227. if(vga->crt[0x13] & 0x100)
  228. vga->crt[0x1B] |= 0x10;
  229. vga->graphics[0x0B] = 0x00;
  230. if(vga->vmz > 1024*1024)
  231. vga->graphics[0x0B] |= 0x20;
  232. if(mode->interlace == 'v'){
  233. vga->crt[0x19] = vga->crt[0x00]/2;
  234. vga->crt[0x1A] |= 0x01;
  235. }
  236. }
  237. static void
  238. load(Vga* vga, Ctlr* ctlr)
  239. {
  240. vgaxo(Seqx, 0x0E, vga->sequencer[0x0E]);
  241. vgaxo(Seqx, 0x1E, vga->sequencer[0x1E]);
  242. if(ctlr->flag & Ulinear)
  243. vga->sequencer[0x07] |= 0xE0;
  244. vgaxo(Seqx, 0x07, vga->sequencer[0x07]);
  245. vgaxo(Seqx, 0x0F, vga->sequencer[0x0F]);
  246. vgaxo(Seqx, 0x16, vga->sequencer[0x16]);
  247. if(vga->mode->interlace == 'v')
  248. vgaxo(Crtx, 0x19, vga->crt[0x19]);
  249. vgaxo(Crtx, 0x1A, vga->crt[0x1A]);
  250. vgaxo(Crtx, 0x1B, vga->crt[0x1B]);
  251. vgaxo(Grx, 0x0B, vga->graphics[0x0B]);
  252. }
  253. static void
  254. dump(Vga* vga, Ctlr* ctlr)
  255. {
  256. int i;
  257. char *name;
  258. name = ctlr->name;
  259. printitem(name, "Seq06");
  260. for(i = 0x06; i < 0x20; i++)
  261. printreg(vga->sequencer[i]);
  262. printitem(name, "Crt19");
  263. for(i = 0x19; i < 0x1E; i++)
  264. printreg(vga->crt[i]);
  265. printitem(name, "Gr09");
  266. for(i = 0x09; i < 0x3A; i++)
  267. printreg(vga->graphics[i]);
  268. printitem(name, "Id Hdr");
  269. printreg(vga->crt[0x27]);
  270. printreg(vga->crt[0x28]);
  271. }
  272. Ctlr clgd542x = {
  273. "clgd542x", /* name */
  274. snarf, /* snarf */
  275. 0, /* options */
  276. init, /* init */
  277. load, /* load */
  278. dump, /* dump */
  279. };
  280. Ctlr clgd542xhwgc = {
  281. "clgd542xhwgc", /* name */
  282. 0, /* snarf */
  283. 0, /* options */
  284. 0, /* init */
  285. 0, /* load */
  286. 0, /* dump */
  287. };