hiqvideo.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. /*
  7. * Chips and Technologies HiQVideo.
  8. * Extensions in the 69000 over the 65550 are not fully taken into account.
  9. * Depths other than 8 are too slow.
  10. */
  11. enum {
  12. Frx = 0x3D0, /* Flat Panel Extensions Index */
  13. Mrx = 0x3D2, /* Multimedia Extensions Index */
  14. Xrx = 0x3D6, /* Configuration Extensions Index */
  15. };
  16. typedef struct {
  17. Pcidev* pci;
  18. uchar fr[256];
  19. uchar mr[256];
  20. uchar xr[256];
  21. } HiQVideo;
  22. static uchar
  23. hiqvideoxi(long port, uchar index)
  24. {
  25. uchar data;
  26. outportb(port, index);
  27. data = inportb(port+1);
  28. return data;
  29. }
  30. static void
  31. hiqvideoxo(long port, uchar index, uchar data)
  32. {
  33. outportb(port, index);
  34. outportb(port+1, data);
  35. }
  36. static void
  37. snarf(Vga* vga, Ctlr* ctlr)
  38. {
  39. int i;
  40. Pcidev *p;
  41. HiQVideo *hqv;
  42. if(vga->private == nil){
  43. vga->private = alloc(sizeof(HiQVideo));
  44. hqv = vga->private;
  45. if((p = pcimatch(nil, 0x102C, 0)) == nil)
  46. error("%s: not found\n", ctlr->name);
  47. switch(p->did){
  48. case 0x00C0: /* 69000 HiQVideo */
  49. vga->f[1] = 135000000;
  50. vga->vmz = 2048*1024;
  51. break;
  52. case 0x00E0: /* 65550 HiQV32 */
  53. case 0x00E4: /* 65554 HiQV32 */
  54. case 0x00E5: /* 65555 HiQV32 */
  55. vga->f[1] = 90000000;
  56. vga->vmz = 2048*1024;
  57. break;
  58. default:
  59. error("%s: DID %4.4uX unsupported\n",
  60. ctlr->name, p->did);
  61. }
  62. hqv->pci = p;
  63. }
  64. hqv = vga->private;
  65. for(i = 0; i < 0x50; i++)
  66. hqv->fr[i] = hiqvideoxi(Frx, i);
  67. for(i = 0; i < 0x60; i++)
  68. hqv->mr[i] = hiqvideoxi(Mrx, i);
  69. for(i = 0x30; i < 0x80; i++)
  70. vga->crt[i] = vgaxi(Crtx, i);
  71. for(i = 0; i < 0x100; i++)
  72. hqv->xr[i] = hiqvideoxi(Xrx, i);
  73. switch(hqv->pci->did){
  74. case 0x00C0: /* 69000 HiQVideo */
  75. vga->f[1] = 135000000;
  76. vga->vmz = 2048*1024;
  77. break;
  78. case 0x00E0: /* 65550 HiQV32 */
  79. case 0x00E4: /* 65554 HiQV32 */
  80. case 0x00E5: /* 65555 HiQV32 */
  81. /*
  82. * Check VCC to determine max clock.
  83. * 5V allows a higher rate.
  84. */
  85. if(hqv->fr[0x0A] & 0x02)
  86. vga->f[1] = 110000000;
  87. else
  88. vga->f[1] = 80000000;
  89. switch((hqv->xr[0x43]>>1) & 0x03){
  90. case 0:
  91. vga->vmz = 1*1024*1024;
  92. break;
  93. case 1:
  94. vga->vmz = 2*1024*1024;
  95. break;
  96. default:
  97. vga->vmz = 16*1024*1024;
  98. break;
  99. }
  100. break;
  101. }
  102. ctlr->flag |= Fsnarf;
  103. }
  104. static void
  105. options(Vga*, Ctlr* ctlr)
  106. {
  107. ctlr->flag |= Hlinear|Foptions;
  108. }
  109. static void
  110. clock(Vga* vga, Ctlr* ctlr)
  111. {
  112. double f, fmin, fvco, m;
  113. ulong n, nmin, nmax, pd, rd;
  114. /*
  115. * Constraints:
  116. * 1. 1MHz <= Fref <= 60MHz
  117. * 2. 150KHz <= Fref/(RD*N) <= 2MHz
  118. * 3. 48MHz < Fvco <= 220MHz
  119. * 4. 3 <= M <= 1023
  120. * 5. 3 <= N <= 1023
  121. */
  122. f = vga->f[0];
  123. /*
  124. * Although pd = 0 is valid, things seems more stable
  125. * starting at 1.
  126. */
  127. for(pd = 1; pd < 6; pd++){
  128. f = vga->f[0]*(1<<pd);
  129. if(f > 48000000 && f <= 220000000)
  130. break;
  131. }
  132. if(pd >= 6)
  133. error("%s: dclk %lud out of range\n", ctlr->name, vga->f[0]);
  134. vga->p[0] = pd;
  135. /*
  136. * The reference divisor has only two possible values, 1 and 4.
  137. */
  138. fmin = f;
  139. for(rd = 1; rd <= 4; rd += 3){
  140. /*
  141. * Find the range for n (constraint 2).
  142. */
  143. for(nmin = 3; nmin <= 1023; nmin++){
  144. if(RefFreq/(rd*nmin) <= 2000000)
  145. break;
  146. }
  147. for(nmax = 1023; nmax >= 3; nmax--){
  148. if(RefFreq/(rd*nmax) >= 150000)
  149. break;
  150. }
  151. /*
  152. * Now find the closest match for M and N.
  153. */
  154. for(n = nmin; n < nmax; n++){
  155. for(m = 3; m <= vga->m[1]; m++){
  156. fvco = (RefFreq*4*m)/(rd*n);
  157. if(fvco < 48000000 || fvco > 220000000)
  158. continue;
  159. fvco -= f;
  160. if(fvco < 0)
  161. fvco = -fvco;
  162. if(fvco < fmin){
  163. fmin = fvco;
  164. vga->m[0] = m;
  165. vga->n[0] = n;
  166. vga->p[0] = pd;
  167. vga->r[0] = rd;
  168. }
  169. }
  170. }
  171. }
  172. }
  173. static void
  174. init(Vga* vga, Ctlr* ctlr)
  175. {
  176. HiQVideo *hqv;
  177. hqv = vga->private;
  178. if(vga->f[0] == 0)
  179. vga->f[0] = vga->mode->frequency;
  180. vga->misc &= ~0x0C;
  181. hqv->fr[0x03] &= ~0x0C;
  182. switch(vga->mode->z){
  183. case 8:
  184. case 16:
  185. case 32:
  186. break;
  187. default:
  188. error("depth %d not supported\n", vga->mode->z);
  189. }
  190. /*
  191. * FR[0x01] == 1 for CRT, 2 for LCD.
  192. * Don't programme the clock if it's an LCD.
  193. */
  194. if((hqv->fr[0x01] & 0x03) == 0x02){
  195. vga->misc |= 0x08;
  196. hqv->fr[0x03] |= 0x08;
  197. }
  198. else{
  199. /*
  200. * Clock bits. If the desired video clock is
  201. * one of the two standard VGA clocks it can just be
  202. * set using bits <3:2> of vga->misc or Fr03,
  203. * otherwise the DCLK PLL needs to be programmed.
  204. */
  205. if(vga->f[0] == VgaFreq0){
  206. /* nothing to do */;
  207. }
  208. else if(vga->f[0] == VgaFreq1){
  209. vga->misc |= 0x04;
  210. hqv->fr[0x03] |= 0x04;
  211. }
  212. else{
  213. if(vga->f[0] > vga->f[1])
  214. error("%s: invalid dclk - %lud\n",
  215. ctlr->name, vga->f[0]);
  216. if((hqv->fr[0x01] & 0x03) != 0x02){
  217. vga->m[1] = 1023;
  218. clock(vga, ctlr);
  219. hqv->xr[0xC8] = (vga->m[0]-2) & 0xFF;
  220. hqv->xr[0xCA] = ((vga->m[0]-2) & 0x300)>>8;
  221. hqv->xr[0xC9] = (vga->n[0]-2) & 0xFF;
  222. hqv->xr[0xCA] |= ((vga->n[0]-2) & 0x300)>>4;
  223. hqv->xr[0xCB] = (vga->p[0]<<4)|(vga->r[0] == 1);
  224. }
  225. vga->misc |= 0x08;
  226. hqv->fr[0x03] |= 0x08;
  227. }
  228. }
  229. if(vga->mode->y >= 480)
  230. vga->misc &= ~0xC0;
  231. /*
  232. * 10 bits should be enough, but set the extended mode anyway.
  233. */
  234. hqv->xr[0x09] |= 0x01;
  235. vga->crt[0x30] = ((vga->mode->vt-2)>>8) & 0x0F;
  236. vga->crt[0x31] = ((vga->mode->y-1)>>8) & 0x0F;
  237. vga->crt[0x32] = (vga->mode->vrs>>8) & 0x0F;
  238. vga->crt[0x33] = (vga->mode->vrs>>8) & 0x0F;
  239. vga->crt[0x38] = (((vga->mode->ht>>3)-5)>>8) & 0x01;
  240. vga->crt[0x3C] = (vga->mode->ehb>>3) & 0xC0;
  241. vga->crt[0x41] = (vga->crt[0x13]>>8) & 0x0F;
  242. vga->crt[0x40] = 0x80;
  243. hqv->xr[0x40] |= 0x03;
  244. hqv->xr[0x80] |= 0x10;
  245. hqv->xr[0x81] &= ~0x0F;
  246. switch(vga->mode->z){
  247. case 8:
  248. hqv->xr[0x81] |= 0x12;
  249. break;
  250. case 16:
  251. hqv->xr[0x81] |= 0x15;
  252. break;
  253. case 32:
  254. hqv->xr[0x81] |= 0x16;
  255. break;
  256. }
  257. hqv->xr[0x0A] = 0x01;
  258. if(vga->linear && (ctlr->flag & Hlinear))
  259. ctlr->flag |= Ulinear;
  260. vga->attribute[0x11] = 0;
  261. ctlr->flag |= Finit;
  262. }
  263. static void
  264. load(Vga* vga, Ctlr* ctlr)
  265. {
  266. HiQVideo *hqv;
  267. hqv = vga->private;
  268. hiqvideoxo(Xrx, 0x0E, 0x00);
  269. while((vgai(Status1) & 0x08) == 0x08)
  270. ;
  271. while((vgai(Status1) & 0x08) == 0)
  272. ;
  273. vgaxo(Seqx, 0x07, 0x00);
  274. /*
  275. * Set the clock if necessary.
  276. */
  277. if((vga->misc & 0x0C) == 0x08 && (hqv->fr[0x01] & 0x03) != 0x02){
  278. vgao(MiscW, vga->misc & ~0x0C);
  279. hiqvideoxo(Frx, 0x03, hqv->fr[0x03] & ~0x0C);
  280. hiqvideoxo(Xrx, 0xC8, hqv->xr[0xC8]);
  281. hiqvideoxo(Xrx, 0xC9, hqv->xr[0xC9]);
  282. hiqvideoxo(Xrx, 0xCA, hqv->xr[0xCA]);
  283. hiqvideoxo(Xrx, 0xCB, hqv->xr[0xCB]);
  284. }
  285. hiqvideoxo(Frx, 0x03, hqv->fr[0x03]);
  286. vgao(MiscW, vga->misc);
  287. hiqvideoxo(Xrx, 0x09, hqv->xr[0x09]);
  288. vgaxo(Crtx, 0x30, vga->crt[0x30]);
  289. vgaxo(Crtx, 0x31, vga->crt[0x31]);
  290. vgaxo(Crtx, 0x32, vga->crt[0x32]);
  291. vgaxo(Crtx, 0x33, vga->crt[0x33]);
  292. vgaxo(Crtx, 0x38, vga->crt[0x38]);
  293. vgaxo(Crtx, 0x3C, vga->crt[0x3C]);
  294. vgaxo(Crtx, 0x41, vga->crt[0x41]);
  295. vgaxo(Crtx, 0x40, vga->crt[0x40]);
  296. hiqvideoxo(Xrx, 0x40, hqv->xr[0x40]);
  297. hiqvideoxo(Xrx, 0x80, hqv->xr[0x80]);
  298. hiqvideoxo(Xrx, 0x81, hqv->xr[0x81]);
  299. if(ctlr->flag & Ulinear){
  300. hqv->xr[0x05] = vga->vmb>>16;
  301. hqv->xr[0x06] = vga->vmb>>24;
  302. hiqvideoxo(Xrx, 0x05, hqv->xr[0x05]);
  303. hiqvideoxo(Xrx, 0x06, hqv->xr[0x06]);
  304. hqv->xr[0x0A] = 0x02;
  305. }
  306. hiqvideoxo(Xrx, 0x0A, hqv->xr[0x0A]);
  307. ctlr->flag |= Fload;
  308. }
  309. static ulong
  310. dumpmclk(uchar data[4])
  311. {
  312. double f, m, n;
  313. int pds, rds;
  314. m = data[0] & 0x7F;
  315. n = data[1] & 0x7F;
  316. pds = 1<<((data[2] & 0x70)>>4);
  317. if(data[2] & 0x01)
  318. rds = 1;
  319. else
  320. rds = 4;
  321. f = (RefFreq*4*(m+2))/(rds*(n+2));
  322. f /= pds;
  323. return f;
  324. }
  325. static ulong
  326. dumpvclk(uchar data[4])
  327. {
  328. double f, m, n;
  329. int pds, rds;
  330. m = ((data[2] & 0x03)<<8)|data[0];
  331. n = (((data[2] & 0x30)>>4)<<8)|data[1];
  332. pds = 1<<((data[3] & 0x70)>>4);
  333. if(data[3] & 0x01)
  334. rds = 1;
  335. else
  336. rds = 4;
  337. f = (RefFreq*4*(m+2))/(rds*(n+2));
  338. f /= pds;
  339. return f;
  340. }
  341. static void
  342. dump(Vga* vga, Ctlr* ctlr)
  343. {
  344. int i;
  345. char *name;
  346. HiQVideo *hqv;
  347. name = ctlr->name;
  348. hqv = vga->private;
  349. printitem(name, "Fr00");
  350. for(i = 0; i < 0x50; i++)
  351. printreg(hqv->fr[i]);
  352. printitem(name, "Mr00");
  353. for(i = 0; i < 0x60; i++)
  354. printreg(hqv->mr[i]);
  355. printitem(name, "Crt30");
  356. for(i = 0x30; i < 0x80; i++)
  357. printreg(vga->crt[i]);
  358. printitem(name, "Xr00");
  359. for(i = 0; i < 0x100; i++)
  360. printreg(hqv->xr[i]);
  361. printitem(ctlr->name, "CLK0");
  362. for(i = 0; i < 4; i++)
  363. printreg(hqv->xr[0xC0+i]);
  364. Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC0]));
  365. printitem(ctlr->name, "CLK1");
  366. for(i = 0; i < 4; i++)
  367. printreg(hqv->xr[0xC4+i]);
  368. Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC4]));
  369. printitem(ctlr->name, "CLK2");
  370. for(i = 0; i < 4; i++)
  371. printreg(hqv->xr[0xC8+i]);
  372. Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC8]));
  373. printitem(ctlr->name, "MCLK");
  374. for(i = 0; i < 4; i++)
  375. printreg(hqv->xr[0xCC+i]);
  376. Bprint(&stdout, "%23ld", dumpmclk(&hqv->xr[0xCC]));
  377. printitem(ctlr->name, "m n pd rd");
  378. Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n",
  379. vga->m[0], vga->n[0], vga->p[0], vga->r[0]);
  380. }
  381. Ctlr hiqvideo = {
  382. "hiqvideo", /* name */
  383. snarf, /* snarf */
  384. options, /* options */
  385. init, /* init */
  386. load, /* load */
  387. dump, /* dump */
  388. };
  389. Ctlr hiqvideohwgc = {
  390. "hiqvideohwgc", /* name */
  391. 0, /* snarf */
  392. 0, /* options */
  393. 0, /* init */
  394. 0, /* load */
  395. 0, /* dump */
  396. };