g450_pll.c 13 KB

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