g450_pll.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. *
  3. * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
  4. *
  5. * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  6. *
  7. * Portions Copyright (c) 2001 Matrox Graphics Inc.
  8. *
  9. * Version: 1.64 2002/06/10
  10. *
  11. * This file is subject to the terms and conditions of the GNU General Public
  12. * License. See the file COPYING in the main directory of this archive for
  13. * more details.
  14. *
  15. */
  16. #include "g450_pll.h"
  17. #include "matroxfb_DAC1064.h"
  18. static inline unsigned int g450_vco2f(unsigned char p, unsigned int fvco) {
  19. return (p & 0x40) ? fvco : fvco >> ((p & 3) + 1);
  20. }
  21. static inline unsigned int g450_f2vco(unsigned char p, unsigned int fin) {
  22. return (p & 0x40) ? fin : fin << ((p & 3) + 1);
  23. }
  24. static unsigned int g450_mnp2vco(CPMINFO unsigned int mnp) {
  25. unsigned int m, n;
  26. m = ((mnp >> 16) & 0x0FF) + 1;
  27. n = ((mnp >> 7) & 0x1FE) + 4;
  28. return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m;
  29. }
  30. unsigned int g450_mnp2f(CPMINFO unsigned int mnp) {
  31. return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp));
  32. }
  33. static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
  34. if (f2 < f1) {
  35. f2 = f1 - f2;
  36. } else {
  37. f2 = f2 - f1;
  38. }
  39. return f2;
  40. }
  41. #define NO_MORE_MNP 0x01FFFFFF
  42. #define G450_MNP_FREQBITS (0xFFFFFF43) /* do not mask high byte so we'll catch NO_MORE_MNP */
  43. static unsigned int g450_nextpll(CPMINFO const struct matrox_pll_limits* pi, unsigned int* fvco, unsigned int mnp) {
  44. unsigned int m, n, p;
  45. unsigned int tvco = *fvco;
  46. m = (mnp >> 16) & 0xFF;
  47. p = mnp & 0xFF;
  48. do {
  49. if (m == 0 || m == 0xFF) {
  50. if (m == 0) {
  51. if (p & 0x40) {
  52. return NO_MORE_MNP;
  53. }
  54. if (p & 3) {
  55. p--;
  56. } else {
  57. p = 0x40;
  58. }
  59. tvco >>= 1;
  60. if (tvco < pi->vcomin) {
  61. return NO_MORE_MNP;
  62. }
  63. *fvco = tvco;
  64. }
  65. p &= 0x43;
  66. if (tvco < 550000) {
  67. /* p |= 0x00; */
  68. } else if (tvco < 700000) {
  69. p |= 0x08;
  70. } else if (tvco < 1000000) {
  71. p |= 0x10;
  72. } else if (tvco < 1150000) {
  73. p |= 0x18;
  74. } else {
  75. p |= 0x20;
  76. }
  77. m = 9;
  78. } else {
  79. m--;
  80. }
  81. n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
  82. } while (n < 0x03 || n > 0x7A);
  83. return (m << 16) | (n << 8) | p;
  84. }
  85. static unsigned int g450_firstpll(CPMINFO const struct matrox_pll_limits* pi, unsigned int* vco, unsigned int fout) {
  86. unsigned int p;
  87. unsigned int vcomax;
  88. vcomax = pi->vcomax;
  89. if (fout > (vcomax / 2)) {
  90. if (fout > vcomax) {
  91. *vco = vcomax;
  92. } else {
  93. *vco = fout;
  94. }
  95. p = 0x40;
  96. } else {
  97. unsigned int tvco;
  98. p = 3;
  99. tvco = g450_f2vco(p, fout);
  100. while (p && (tvco > vcomax)) {
  101. p--;
  102. tvco >>= 1;
  103. }
  104. if (tvco < pi->vcomin) {
  105. tvco = pi->vcomin;
  106. }
  107. *vco = tvco;
  108. }
  109. return g450_nextpll(PMINFO pi, vco, 0xFF0000 | p);
  110. }
  111. static inline unsigned int g450_setpll(CPMINFO unsigned int mnp, unsigned int pll) {
  112. switch (pll) {
  113. case M_PIXEL_PLL_A:
  114. matroxfb_DAC_out(PMINFO M1064_XPIXPLLAM, mnp >> 16);
  115. matroxfb_DAC_out(PMINFO M1064_XPIXPLLAN, mnp >> 8);
  116. matroxfb_DAC_out(PMINFO M1064_XPIXPLLAP, mnp);
  117. return M1064_XPIXPLLSTAT;
  118. case M_PIXEL_PLL_B:
  119. matroxfb_DAC_out(PMINFO M1064_XPIXPLLBM, mnp >> 16);
  120. matroxfb_DAC_out(PMINFO M1064_XPIXPLLBN, mnp >> 8);
  121. matroxfb_DAC_out(PMINFO M1064_XPIXPLLBP, mnp);
  122. return M1064_XPIXPLLSTAT;
  123. case M_PIXEL_PLL_C:
  124. matroxfb_DAC_out(PMINFO M1064_XPIXPLLCM, mnp >> 16);
  125. matroxfb_DAC_out(PMINFO M1064_XPIXPLLCN, mnp >> 8);
  126. matroxfb_DAC_out(PMINFO M1064_XPIXPLLCP, mnp);
  127. return M1064_XPIXPLLSTAT;
  128. case M_SYSTEM_PLL:
  129. matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLM, mnp >> 16);
  130. matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLN, mnp >> 8);
  131. matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLP, mnp);
  132. return DAC1064_XSYSPLLSTAT;
  133. case M_VIDEO_PLL:
  134. matroxfb_DAC_out(PMINFO M1064_XVIDPLLM, mnp >> 16);
  135. matroxfb_DAC_out(PMINFO M1064_XVIDPLLN, mnp >> 8);
  136. matroxfb_DAC_out(PMINFO M1064_XVIDPLLP, mnp);
  137. return M1064_XVIDPLLSTAT;
  138. }
  139. return 0;
  140. }
  141. static inline unsigned int g450_cmppll(CPMINFO unsigned int mnp, unsigned int pll) {
  142. unsigned char m = mnp >> 16;
  143. unsigned char n = mnp >> 8;
  144. unsigned char p = mnp;
  145. switch (pll) {
  146. case M_PIXEL_PLL_A:
  147. return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLAM) != m ||
  148. matroxfb_DAC_in(PMINFO M1064_XPIXPLLAN) != n ||
  149. matroxfb_DAC_in(PMINFO M1064_XPIXPLLAP) != p);
  150. case M_PIXEL_PLL_B:
  151. return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLBM) != m ||
  152. matroxfb_DAC_in(PMINFO M1064_XPIXPLLBN) != n ||
  153. matroxfb_DAC_in(PMINFO M1064_XPIXPLLBP) != p);
  154. case M_PIXEL_PLL_C:
  155. return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM) != m ||
  156. matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN) != n ||
  157. matroxfb_DAC_in(PMINFO M1064_XPIXPLLCP) != p);
  158. case M_SYSTEM_PLL:
  159. return (matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLM) != m ||
  160. matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLN) != n ||
  161. matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLP) != p);
  162. case M_VIDEO_PLL:
  163. return (matroxfb_DAC_in(PMINFO M1064_XVIDPLLM) != m ||
  164. matroxfb_DAC_in(PMINFO M1064_XVIDPLLN) != n ||
  165. matroxfb_DAC_in(PMINFO M1064_XVIDPLLP) != p);
  166. }
  167. return 1;
  168. }
  169. static inline int g450_isplllocked(CPMINFO unsigned int regidx) {
  170. unsigned int j;
  171. for (j = 0; j < 1000; j++) {
  172. if (matroxfb_DAC_in(PMINFO regidx) & 0x40) {
  173. unsigned int r = 0;
  174. int i;
  175. for (i = 0; i < 100; i++) {
  176. r += matroxfb_DAC_in(PMINFO regidx) & 0x40;
  177. }
  178. return r >= (90 * 0x40);
  179. }
  180. /* udelay(1)... but DAC_in is much slower... */
  181. }
  182. return 0;
  183. }
  184. static int g450_testpll(CPMINFO unsigned int mnp, unsigned int pll) {
  185. return g450_isplllocked(PMINFO g450_setpll(PMINFO mnp, pll));
  186. }
  187. static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsigned int pll) {
  188. switch (pll) {
  189. case M_SYSTEM_PLL:
  190. hw->DACclk[3] = mnp >> 16;
  191. hw->DACclk[4] = mnp >> 8;
  192. hw->DACclk[5] = mnp;
  193. break;
  194. }
  195. }
  196. void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
  197. if (g450_cmppll(PMINFO mnp, pll)) {
  198. g450_setpll(PMINFO mnp, pll);
  199. }
  200. }
  201. static inline unsigned int g450_findworkingpll(WPMINFO unsigned int pll, unsigned int* mnparray, unsigned int mnpcount) {
  202. unsigned int found = 0;
  203. unsigned int idx;
  204. unsigned int mnpfound = mnparray[0];
  205. for (idx = 0; idx < mnpcount; idx++) {
  206. unsigned int sarray[3];
  207. unsigned int *sptr;
  208. {
  209. unsigned int mnp;
  210. sptr = sarray;
  211. mnp = mnparray[idx];
  212. if (mnp & 0x38) {
  213. *sptr++ = mnp - 8;
  214. }
  215. if ((mnp & 0x38) != 0x38) {
  216. *sptr++ = mnp + 8;
  217. }
  218. *sptr = mnp;
  219. }
  220. while (sptr >= sarray) {
  221. unsigned int mnp = *sptr--;
  222. if (g450_testpll(PMINFO mnp - 0x0300, pll) &&
  223. g450_testpll(PMINFO mnp + 0x0300, pll) &&
  224. g450_testpll(PMINFO mnp - 0x0200, pll) &&
  225. g450_testpll(PMINFO mnp + 0x0200, pll) &&
  226. g450_testpll(PMINFO mnp - 0x0100, pll) &&
  227. g450_testpll(PMINFO mnp + 0x0100, pll)) {
  228. if (g450_testpll(PMINFO mnp, pll)) {
  229. return mnp;
  230. }
  231. } else if (!found && g450_testpll(PMINFO mnp, pll)) {
  232. mnpfound = mnp;
  233. found = 1;
  234. }
  235. }
  236. }
  237. g450_setpll(PMINFO mnpfound, pll);
  238. return mnpfound;
  239. }
  240. static void g450_addcache(struct matrox_pll_cache* ci, unsigned int mnp_key, unsigned int mnp_value) {
  241. if (++ci->valid > ARRAY_SIZE(ci->data)) {
  242. ci->valid = ARRAY_SIZE(ci->data);
  243. }
  244. memmove(ci->data + 1, ci->data, (ci->valid - 1) * sizeof(*ci->data));
  245. ci->data[0].mnp_key = mnp_key & G450_MNP_FREQBITS;
  246. ci->data[0].mnp_value = mnp_value;
  247. }
  248. static int g450_checkcache(WPMINFO struct matrox_pll_cache* ci, unsigned int mnp_key) {
  249. unsigned int i;
  250. mnp_key &= G450_MNP_FREQBITS;
  251. for (i = 0; i < ci->valid; i++) {
  252. if (ci->data[i].mnp_key == mnp_key) {
  253. unsigned int mnp;
  254. mnp = ci->data[i].mnp_value;
  255. if (i) {
  256. memmove(ci->data + 1, ci->data, i * sizeof(*ci->data));
  257. ci->data[0].mnp_key = mnp_key;
  258. ci->data[0].mnp_value = mnp;
  259. }
  260. return mnp;
  261. }
  262. }
  263. return NO_MORE_MNP;
  264. }
  265. static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
  266. unsigned int* mnparray, unsigned int* deltaarray) {
  267. unsigned int mnpcount;
  268. unsigned int pixel_vco;
  269. const struct matrox_pll_limits* pi;
  270. struct matrox_pll_cache* ci;
  271. pixel_vco = 0;
  272. switch (pll) {
  273. case M_PIXEL_PLL_A:
  274. case M_PIXEL_PLL_B:
  275. case M_PIXEL_PLL_C:
  276. {
  277. u_int8_t tmp, xpwrctrl;
  278. unsigned long flags;
  279. matroxfb_DAC_lock_irqsave(flags);
  280. xpwrctrl = matroxfb_DAC_in(PMINFO M1064_XPWRCTRL);
  281. matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, xpwrctrl & ~M1064_XPWRCTRL_PANELPDN);
  282. mga_outb(M_SEQ_INDEX, M_SEQ1);
  283. mga_outb(M_SEQ_DATA, mga_inb(M_SEQ_DATA) | M_SEQ1_SCROFF);
  284. tmp = matroxfb_DAC_in(PMINFO M1064_XPIXCLKCTRL);
  285. tmp |= M1064_XPIXCLKCTRL_DIS;
  286. if (!(tmp & M1064_XPIXCLKCTRL_PLL_UP)) {
  287. tmp |= M1064_XPIXCLKCTRL_PLL_UP;
  288. }
  289. matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp);
  290. /* DVI PLL preferred for frequencies up to
  291. panel link max, standard PLL otherwise */
  292. if (fout >= MINFO->max_pixel_clock_panellink)
  293. tmp = 0;
  294. else tmp =
  295. M1064_XDVICLKCTRL_DVIDATAPATHSEL |
  296. M1064_XDVICLKCTRL_C1DVICLKSEL |
  297. M1064_XDVICLKCTRL_C1DVICLKEN |
  298. M1064_XDVICLKCTRL_DVILOOPCTL |
  299. M1064_XDVICLKCTRL_P1LOOPBWDTCTL;
  300. matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL,tmp);
  301. matroxfb_DAC_out(PMINFO M1064_XPWRCTRL,
  302. xpwrctrl);
  303. matroxfb_DAC_unlock_irqrestore(flags);
  304. }
  305. {
  306. u_int8_t misc;
  307. misc = mga_inb(M_MISC_REG_READ) & ~0x0C;
  308. switch (pll) {
  309. case M_PIXEL_PLL_A:
  310. break;
  311. case M_PIXEL_PLL_B:
  312. misc |= 0x04;
  313. break;
  314. default:
  315. misc |= 0x0C;
  316. break;
  317. }
  318. mga_outb(M_MISC_REG, misc);
  319. }
  320. pi = &ACCESS_FBINFO(limits.pixel);
  321. ci = &ACCESS_FBINFO(cache.pixel);
  322. break;
  323. case M_SYSTEM_PLL:
  324. {
  325. u_int32_t opt;
  326. pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &opt);
  327. if (!(opt & 0x20)) {
  328. pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, opt | 0x20);
  329. }
  330. }
  331. pi = &ACCESS_FBINFO(limits.system);
  332. ci = &ACCESS_FBINFO(cache.system);
  333. break;
  334. case M_VIDEO_PLL:
  335. {
  336. u_int8_t tmp;
  337. unsigned int mnp;
  338. unsigned long flags;
  339. matroxfb_DAC_lock_irqsave(flags);
  340. tmp = matroxfb_DAC_in(PMINFO M1064_XPWRCTRL);
  341. if (!(tmp & 2)) {
  342. matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, tmp | 2);
  343. }
  344. mnp = matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM) << 16;
  345. mnp |= matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN) << 8;
  346. pixel_vco = g450_mnp2vco(PMINFO mnp);
  347. matroxfb_DAC_unlock_irqrestore(flags);
  348. }
  349. pi = &ACCESS_FBINFO(limits.video);
  350. ci = &ACCESS_FBINFO(cache.video);
  351. break;
  352. default:
  353. return -EINVAL;
  354. }
  355. mnpcount = 0;
  356. {
  357. unsigned int mnp;
  358. unsigned int xvco;
  359. for(mnp = g450_firstpll(PMINFO pi, &xvco, fout); mnp != NO_MORE_MNP; mnp = g450_nextpll(PMINFO pi, &xvco, mnp)) {
  360. unsigned int idx;
  361. unsigned int vco;
  362. unsigned int delta;
  363. vco = g450_mnp2vco(PMINFO mnp);
  364. #if 0
  365. if (pll == M_VIDEO_PLL) {
  366. unsigned int big, small;
  367. if (vco < pixel_vco) {
  368. small = vco;
  369. big = pixel_vco;
  370. } else {
  371. small = pixel_vco;
  372. big = vco;
  373. }
  374. while (big > small) {
  375. big >>= 1;
  376. }
  377. if (big == small) {
  378. continue;
  379. }
  380. }
  381. #endif
  382. delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
  383. for (idx = mnpcount; idx > 0; idx--) {
  384. /* == is important; due to nextpll algorithm we get
  385. sorted equally good frequencies from lower VCO
  386. frequency to higher - with <= lowest wins, while
  387. with < highest one wins */
  388. if (delta <= deltaarray[idx-1]) {
  389. /* all else being equal except VCO,
  390. * choose VCO not near (within 1/16th or so) VCOmin
  391. * (freqs near VCOmin aren't as stable)
  392. */
  393. if (delta == deltaarray[idx-1]
  394. && vco != g450_mnp2vco(PMINFO mnparray[idx-1])
  395. && vco < (pi->vcomin * 17 / 16)) {
  396. break;
  397. }
  398. mnparray[idx] = mnparray[idx-1];
  399. deltaarray[idx] = deltaarray[idx-1];
  400. } else {
  401. break;
  402. }
  403. }
  404. mnparray[idx] = mnp;
  405. deltaarray[idx] = delta;
  406. mnpcount++;
  407. }
  408. }
  409. /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
  410. if (!mnpcount) {
  411. return -EBUSY;
  412. }
  413. {
  414. unsigned long flags;
  415. unsigned int mnp;
  416. matroxfb_DAC_lock_irqsave(flags);
  417. mnp = g450_checkcache(PMINFO ci, mnparray[0]);
  418. if (mnp != NO_MORE_MNP) {
  419. matroxfb_g450_setpll_cond(PMINFO mnp, pll);
  420. } else {
  421. mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
  422. g450_addcache(ci, mnparray[0], mnp);
  423. }
  424. updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
  425. matroxfb_DAC_unlock_irqrestore(flags);
  426. return mnp;
  427. }
  428. }
  429. /* It must be greater than number of possible PLL values.
  430. * Currently there is 5(p) * 10(m) = 50 possible values. */
  431. #define MNP_TABLE_SIZE 64
  432. int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll) {
  433. unsigned int* arr;
  434. arr = kmalloc(sizeof(*arr) * MNP_TABLE_SIZE * 2, GFP_KERNEL);
  435. if (arr) {
  436. int r;
  437. r = __g450_setclk(PMINFO fout, pll, arr, arr + MNP_TABLE_SIZE);
  438. kfree(arr);
  439. return r;
  440. }
  441. return -ENOMEM;
  442. }
  443. EXPORT_SYMBOL(matroxfb_g450_setclk);
  444. EXPORT_SYMBOL(g450_mnp2f);
  445. EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
  446. MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
  447. MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
  448. MODULE_LICENSE("GPL");