PageRenderTime 62ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/video/matrox/g450_pll.c

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