3 * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
5 * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
7 * Portions Copyright (c) 2001 Matrox Graphics Inc.
9 * Version: 1.64 2002/06/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
18 #include "matroxfb_DAC1064.h"
20 static inline unsigned int g450_vco2f(unsigned char p
, unsigned int fvco
) {
21 return (p
& 0x40) ? fvco
: fvco
>> ((p
& 3) + 1);
24 static inline unsigned int g450_f2vco(unsigned char p
, unsigned int fin
) {
25 return (p
& 0x40) ? fin
: fin
<< ((p
& 3) + 1);
28 static unsigned int g450_mnp2vco(const struct matrox_fb_info
*minfo
,
33 m
= ((mnp
>> 16) & 0x0FF) + 1;
34 n
= ((mnp
>> 7) & 0x1FE) + 4;
35 return (minfo
->features
.pll
.ref_freq
* n
+ (m
>> 1)) / m
;
38 unsigned int g450_mnp2f(const struct matrox_fb_info
*minfo
, unsigned int mnp
)
40 return g450_vco2f(mnp
, g450_mnp2vco(minfo
, mnp
));
43 static inline unsigned int pll_freq_delta(unsigned int f1
, unsigned int f2
) {
52 #define NO_MORE_MNP 0x01FFFFFF
53 #define G450_MNP_FREQBITS (0xFFFFFF43) /* do not mask high byte so we'll catch NO_MORE_MNP */
55 static unsigned int g450_nextpll(const struct matrox_fb_info
*minfo
,
56 const struct matrox_pll_limits
*pi
,
57 unsigned int *fvco
, unsigned int mnp
)
60 unsigned int tvco
= *fvco
;
62 m
= (mnp
>> 16) & 0xFF;
66 if (m
== 0 || m
== 0xFF) {
77 if (tvco
< pi
->vcomin
) {
86 } else if (tvco
< 700000) {
88 } else if (tvco
< 1000000) {
90 } else if (tvco
< 1150000) {
99 n
= ((tvco
* (m
+1) + minfo
->features
.pll
.ref_freq
) / (minfo
->features
.pll
.ref_freq
* 2)) - 2;
100 } while (n
< 0x03 || n
> 0x7A);
101 return (m
<< 16) | (n
<< 8) | p
;
104 static unsigned int g450_firstpll(const struct matrox_fb_info
*minfo
,
105 const struct matrox_pll_limits
*pi
,
106 unsigned int *vco
, unsigned int fout
)
112 if (fout
> (vcomax
/ 2)) {
123 tvco
= g450_f2vco(p
, fout
);
124 while (p
&& (tvco
> vcomax
)) {
128 if (tvco
< pi
->vcomin
) {
133 return g450_nextpll(minfo
, pi
, vco
, 0xFF0000 | p
);
136 static inline unsigned int g450_setpll(const struct matrox_fb_info
*minfo
,
137 unsigned int mnp
, unsigned int pll
)
141 matroxfb_DAC_out(minfo
, M1064_XPIXPLLAM
, mnp
>> 16);
142 matroxfb_DAC_out(minfo
, M1064_XPIXPLLAN
, mnp
>> 8);
143 matroxfb_DAC_out(minfo
, M1064_XPIXPLLAP
, mnp
);
144 return M1064_XPIXPLLSTAT
;
147 matroxfb_DAC_out(minfo
, M1064_XPIXPLLBM
, mnp
>> 16);
148 matroxfb_DAC_out(minfo
, M1064_XPIXPLLBN
, mnp
>> 8);
149 matroxfb_DAC_out(minfo
, M1064_XPIXPLLBP
, mnp
);
150 return M1064_XPIXPLLSTAT
;
153 matroxfb_DAC_out(minfo
, M1064_XPIXPLLCM
, mnp
>> 16);
154 matroxfb_DAC_out(minfo
, M1064_XPIXPLLCN
, mnp
>> 8);
155 matroxfb_DAC_out(minfo
, M1064_XPIXPLLCP
, mnp
);
156 return M1064_XPIXPLLSTAT
;
159 matroxfb_DAC_out(minfo
, DAC1064_XSYSPLLM
, mnp
>> 16);
160 matroxfb_DAC_out(minfo
, DAC1064_XSYSPLLN
, mnp
>> 8);
161 matroxfb_DAC_out(minfo
, DAC1064_XSYSPLLP
, mnp
);
162 return DAC1064_XSYSPLLSTAT
;
165 matroxfb_DAC_out(minfo
, M1064_XVIDPLLM
, mnp
>> 16);
166 matroxfb_DAC_out(minfo
, M1064_XVIDPLLN
, mnp
>> 8);
167 matroxfb_DAC_out(minfo
, M1064_XVIDPLLP
, mnp
);
168 return M1064_XVIDPLLSTAT
;
173 static inline unsigned int g450_cmppll(const struct matrox_fb_info
*minfo
,
174 unsigned int mnp
, unsigned int pll
)
176 unsigned char m
= mnp
>> 16;
177 unsigned char n
= mnp
>> 8;
178 unsigned char p
= mnp
;
182 return (matroxfb_DAC_in(minfo
, M1064_XPIXPLLAM
) != m
||
183 matroxfb_DAC_in(minfo
, M1064_XPIXPLLAN
) != n
||
184 matroxfb_DAC_in(minfo
, M1064_XPIXPLLAP
) != p
);
187 return (matroxfb_DAC_in(minfo
, M1064_XPIXPLLBM
) != m
||
188 matroxfb_DAC_in(minfo
, M1064_XPIXPLLBN
) != n
||
189 matroxfb_DAC_in(minfo
, M1064_XPIXPLLBP
) != p
);
192 return (matroxfb_DAC_in(minfo
, M1064_XPIXPLLCM
) != m
||
193 matroxfb_DAC_in(minfo
, M1064_XPIXPLLCN
) != n
||
194 matroxfb_DAC_in(minfo
, M1064_XPIXPLLCP
) != p
);
197 return (matroxfb_DAC_in(minfo
, DAC1064_XSYSPLLM
) != m
||
198 matroxfb_DAC_in(minfo
, DAC1064_XSYSPLLN
) != n
||
199 matroxfb_DAC_in(minfo
, DAC1064_XSYSPLLP
) != p
);
202 return (matroxfb_DAC_in(minfo
, M1064_XVIDPLLM
) != m
||
203 matroxfb_DAC_in(minfo
, M1064_XVIDPLLN
) != n
||
204 matroxfb_DAC_in(minfo
, M1064_XVIDPLLP
) != p
);
209 static inline int g450_isplllocked(const struct matrox_fb_info
*minfo
,
214 for (j
= 0; j
< 1000; j
++) {
215 if (matroxfb_DAC_in(minfo
, regidx
) & 0x40) {
219 for (i
= 0; i
< 100; i
++) {
220 r
+= matroxfb_DAC_in(minfo
, regidx
) & 0x40;
222 return r
>= (90 * 0x40);
224 /* udelay(1)... but DAC_in is much slower... */
229 static int g450_testpll(const struct matrox_fb_info
*minfo
, unsigned int mnp
,
232 return g450_isplllocked(minfo
, g450_setpll(minfo
, mnp
, pll
));
235 static void updatehwstate_clk(struct matrox_hw_state
* hw
, unsigned int mnp
, unsigned int pll
) {
238 hw
->DACclk
[3] = mnp
>> 16;
239 hw
->DACclk
[4] = mnp
>> 8;
245 void matroxfb_g450_setpll_cond(struct matrox_fb_info
*minfo
, unsigned int mnp
,
248 if (g450_cmppll(minfo
, mnp
, pll
)) {
249 g450_setpll(minfo
, mnp
, pll
);
253 static inline unsigned int g450_findworkingpll(struct matrox_fb_info
*minfo
,
255 unsigned int *mnparray
,
256 unsigned int mnpcount
)
258 unsigned int found
= 0;
260 unsigned int mnpfound
= mnparray
[0];
262 for (idx
= 0; idx
< mnpcount
; idx
++) {
263 unsigned int sarray
[3];
273 if ((mnp
& 0x38) != 0x38) {
278 while (sptr
>= sarray
) {
279 unsigned int mnp
= *sptr
--;
281 if (g450_testpll(minfo
, mnp
- 0x0300, pll
) &&
282 g450_testpll(minfo
, mnp
+ 0x0300, pll
) &&
283 g450_testpll(minfo
, mnp
- 0x0200, pll
) &&
284 g450_testpll(minfo
, mnp
+ 0x0200, pll
) &&
285 g450_testpll(minfo
, mnp
- 0x0100, pll
) &&
286 g450_testpll(minfo
, mnp
+ 0x0100, pll
)) {
287 if (g450_testpll(minfo
, mnp
, pll
)) {
290 } else if (!found
&& g450_testpll(minfo
, mnp
, pll
)) {
296 g450_setpll(minfo
, mnpfound
, pll
);
300 static void g450_addcache(struct matrox_pll_cache
* ci
, unsigned int mnp_key
, unsigned int mnp_value
) {
301 if (++ci
->valid
> ARRAY_SIZE(ci
->data
)) {
302 ci
->valid
= ARRAY_SIZE(ci
->data
);
304 memmove(ci
->data
+ 1, ci
->data
, (ci
->valid
- 1) * sizeof(*ci
->data
));
305 ci
->data
[0].mnp_key
= mnp_key
& G450_MNP_FREQBITS
;
306 ci
->data
[0].mnp_value
= mnp_value
;
309 static int g450_checkcache(struct matrox_fb_info
*minfo
,
310 struct matrox_pll_cache
*ci
, unsigned int mnp_key
)
314 mnp_key
&= G450_MNP_FREQBITS
;
315 for (i
= 0; i
< ci
->valid
; i
++) {
316 if (ci
->data
[i
].mnp_key
== mnp_key
) {
319 mnp
= ci
->data
[i
].mnp_value
;
321 memmove(ci
->data
+ 1, ci
->data
, i
* sizeof(*ci
->data
));
322 ci
->data
[0].mnp_key
= mnp_key
;
323 ci
->data
[0].mnp_value
= mnp
;
331 static int __g450_setclk(struct matrox_fb_info
*minfo
, unsigned int fout
,
332 unsigned int pll
, unsigned int *mnparray
,
333 unsigned int *deltaarray
)
335 unsigned int mnpcount
;
336 unsigned int pixel_vco
;
337 const struct matrox_pll_limits
* pi
;
338 struct matrox_pll_cache
* ci
;
346 u_int8_t tmp
, xpwrctrl
;
349 matroxfb_DAC_lock_irqsave(flags
);
351 xpwrctrl
= matroxfb_DAC_in(minfo
, M1064_XPWRCTRL
);
352 matroxfb_DAC_out(minfo
, M1064_XPWRCTRL
, xpwrctrl
& ~M1064_XPWRCTRL_PANELPDN
);
353 mga_outb(M_SEQ_INDEX
, M_SEQ1
);
354 mga_outb(M_SEQ_DATA
, mga_inb(M_SEQ_DATA
) | M_SEQ1_SCROFF
);
355 tmp
= matroxfb_DAC_in(minfo
, M1064_XPIXCLKCTRL
);
356 tmp
|= M1064_XPIXCLKCTRL_DIS
;
357 if (!(tmp
& M1064_XPIXCLKCTRL_PLL_UP
)) {
358 tmp
|= M1064_XPIXCLKCTRL_PLL_UP
;
360 matroxfb_DAC_out(minfo
, M1064_XPIXCLKCTRL
, tmp
);
361 /* DVI PLL preferred for frequencies up to
362 panel link max, standard PLL otherwise */
363 if (fout
>= minfo
->max_pixel_clock_panellink
)
366 M1064_XDVICLKCTRL_DVIDATAPATHSEL
|
367 M1064_XDVICLKCTRL_C1DVICLKSEL
|
368 M1064_XDVICLKCTRL_C1DVICLKEN
|
369 M1064_XDVICLKCTRL_DVILOOPCTL
|
370 M1064_XDVICLKCTRL_P1LOOPBWDTCTL
;
371 /* Setting this breaks PC systems so don't do it */
372 /* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */
373 matroxfb_DAC_out(minfo
, M1064_XPWRCTRL
,
376 matroxfb_DAC_unlock_irqrestore(flags
);
381 misc
= mga_inb(M_MISC_REG_READ
) & ~0x0C;
392 mga_outb(M_MISC_REG
, misc
);
394 pi
= &minfo
->limits
.pixel
;
395 ci
= &minfo
->cache
.pixel
;
401 pci_read_config_dword(minfo
->pcidev
, PCI_OPTION_REG
, &opt
);
403 pci_write_config_dword(minfo
->pcidev
, PCI_OPTION_REG
, opt
| 0x20);
406 pi
= &minfo
->limits
.system
;
407 ci
= &minfo
->cache
.system
;
415 matroxfb_DAC_lock_irqsave(flags
);
416 tmp
= matroxfb_DAC_in(minfo
, M1064_XPWRCTRL
);
418 matroxfb_DAC_out(minfo
, M1064_XPWRCTRL
, tmp
| 2);
421 mnp
= matroxfb_DAC_in(minfo
, M1064_XPIXPLLCM
) << 16;
422 mnp
|= matroxfb_DAC_in(minfo
, M1064_XPIXPLLCN
) << 8;
423 pixel_vco
= g450_mnp2vco(minfo
, mnp
);
424 matroxfb_DAC_unlock_irqrestore(flags
);
426 pi
= &minfo
->limits
.video
;
427 ci
= &minfo
->cache
.video
;
438 for (mnp
= g450_firstpll(minfo
, pi
, &xvco
, fout
); mnp
!= NO_MORE_MNP
; mnp
= g450_nextpll(minfo
, pi
, &xvco
, mnp
)) {
443 vco
= g450_mnp2vco(minfo
, mnp
);
445 if (pll
== M_VIDEO_PLL
) {
446 unsigned int big
, small
;
448 if (vco
< pixel_vco
) {
455 while (big
> small
) {
463 delta
= pll_freq_delta(fout
, g450_vco2f(mnp
, vco
));
464 for (idx
= mnpcount
; idx
> 0; idx
--) {
465 /* == is important; due to nextpll algorithm we get
466 sorted equally good frequencies from lower VCO
467 frequency to higher - with <= lowest wins, while
468 with < highest one wins */
469 if (delta
<= deltaarray
[idx
-1]) {
470 /* all else being equal except VCO,
471 * choose VCO not near (within 1/16th or so) VCOmin
472 * (freqs near VCOmin aren't as stable)
474 if (delta
== deltaarray
[idx
-1]
475 && vco
!= g450_mnp2vco(minfo
, mnparray
[idx
-1])
476 && vco
< (pi
->vcomin
* 17 / 16)) {
479 mnparray
[idx
] = mnparray
[idx
-1];
480 deltaarray
[idx
] = deltaarray
[idx
-1];
486 deltaarray
[idx
] = delta
;
490 /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
498 matroxfb_DAC_lock_irqsave(flags
);
499 mnp
= g450_checkcache(minfo
, ci
, mnparray
[0]);
500 if (mnp
!= NO_MORE_MNP
) {
501 matroxfb_g450_setpll_cond(minfo
, mnp
, pll
);
503 mnp
= g450_findworkingpll(minfo
, pll
, mnparray
, mnpcount
);
504 g450_addcache(ci
, mnparray
[0], mnp
);
506 updatehwstate_clk(&minfo
->hw
, mnp
, pll
);
507 matroxfb_DAC_unlock_irqrestore(flags
);
512 /* It must be greater than number of possible PLL values.
513 * Currently there is 5(p) * 10(m) = 50 possible values. */
514 #define MNP_TABLE_SIZE 64
516 int matroxfb_g450_setclk(struct matrox_fb_info
*minfo
, unsigned int fout
,
521 arr
= kmalloc(sizeof(*arr
) * MNP_TABLE_SIZE
* 2, GFP_KERNEL
);
525 r
= __g450_setclk(minfo
, fout
, pll
, arr
, arr
+ MNP_TABLE_SIZE
);
532 EXPORT_SYMBOL(matroxfb_g450_setclk
);
533 EXPORT_SYMBOL(g450_mnp2f
);
534 EXPORT_SYMBOL(matroxfb_g450_setpll_cond
);
536 MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
537 MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
539 MODULE_LICENSE("GPL");