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(CPMINFO
unsigned int mnp
) {
31 m
= ((mnp
>> 16) & 0x0FF) + 1;
32 n
= ((mnp
>> 7) & 0x1FE) + 4;
33 return (ACCESS_FBINFO(features
).pll
.ref_freq
* n
+ (m
>> 1)) / m
;
36 unsigned int g450_mnp2f(CPMINFO
unsigned int mnp
) {
37 return g450_vco2f(mnp
, g450_mnp2vco(PMINFO mnp
));
40 static inline unsigned int pll_freq_delta(unsigned int f1
, unsigned int f2
) {
49 #define NO_MORE_MNP 0x01FFFFFF
50 #define G450_MNP_FREQBITS (0xFFFFFF43) /* do not mask high byte so we'll catch NO_MORE_MNP */
52 static unsigned int g450_nextpll(CPMINFO
const struct matrox_pll_limits
* pi
, unsigned int* fvco
, unsigned int mnp
) {
54 unsigned int tvco
= *fvco
;
56 m
= (mnp
>> 16) & 0xFF;
60 if (m
== 0 || m
== 0xFF) {
71 if (tvco
< pi
->vcomin
) {
80 } else if (tvco
< 700000) {
82 } else if (tvco
< 1000000) {
84 } else if (tvco
< 1150000) {
93 n
= ((tvco
* (m
+1) + ACCESS_FBINFO(features
).pll
.ref_freq
) / (ACCESS_FBINFO(features
).pll
.ref_freq
* 2)) - 2;
94 } while (n
< 0x03 || n
> 0x7A);
95 return (m
<< 16) | (n
<< 8) | p
;
98 static unsigned int g450_firstpll(CPMINFO
const struct matrox_pll_limits
* pi
, unsigned int* vco
, unsigned int fout
) {
103 if (fout
> (vcomax
/ 2)) {
114 tvco
= g450_f2vco(p
, fout
);
115 while (p
&& (tvco
> vcomax
)) {
119 if (tvco
< pi
->vcomin
) {
124 return g450_nextpll(PMINFO pi
, vco
, 0xFF0000 | p
);
127 static inline unsigned int g450_setpll(CPMINFO
unsigned int mnp
, unsigned int pll
) {
130 matroxfb_DAC_out(PMINFO M1064_XPIXPLLAM
, mnp
>> 16);
131 matroxfb_DAC_out(PMINFO M1064_XPIXPLLAN
, mnp
>> 8);
132 matroxfb_DAC_out(PMINFO M1064_XPIXPLLAP
, mnp
);
133 return M1064_XPIXPLLSTAT
;
136 matroxfb_DAC_out(PMINFO M1064_XPIXPLLBM
, mnp
>> 16);
137 matroxfb_DAC_out(PMINFO M1064_XPIXPLLBN
, mnp
>> 8);
138 matroxfb_DAC_out(PMINFO M1064_XPIXPLLBP
, mnp
);
139 return M1064_XPIXPLLSTAT
;
142 matroxfb_DAC_out(PMINFO M1064_XPIXPLLCM
, mnp
>> 16);
143 matroxfb_DAC_out(PMINFO M1064_XPIXPLLCN
, mnp
>> 8);
144 matroxfb_DAC_out(PMINFO M1064_XPIXPLLCP
, mnp
);
145 return M1064_XPIXPLLSTAT
;
148 matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLM
, mnp
>> 16);
149 matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLN
, mnp
>> 8);
150 matroxfb_DAC_out(PMINFO DAC1064_XSYSPLLP
, mnp
);
151 return DAC1064_XSYSPLLSTAT
;
154 matroxfb_DAC_out(PMINFO M1064_XVIDPLLM
, mnp
>> 16);
155 matroxfb_DAC_out(PMINFO M1064_XVIDPLLN
, mnp
>> 8);
156 matroxfb_DAC_out(PMINFO M1064_XVIDPLLP
, mnp
);
157 return M1064_XVIDPLLSTAT
;
162 static inline unsigned int g450_cmppll(CPMINFO
unsigned int mnp
, unsigned int pll
) {
163 unsigned char m
= mnp
>> 16;
164 unsigned char n
= mnp
>> 8;
165 unsigned char p
= mnp
;
169 return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLAM
) != m
||
170 matroxfb_DAC_in(PMINFO M1064_XPIXPLLAN
) != n
||
171 matroxfb_DAC_in(PMINFO M1064_XPIXPLLAP
) != p
);
174 return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLBM
) != m
||
175 matroxfb_DAC_in(PMINFO M1064_XPIXPLLBN
) != n
||
176 matroxfb_DAC_in(PMINFO M1064_XPIXPLLBP
) != p
);
179 return (matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM
) != m
||
180 matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN
) != n
||
181 matroxfb_DAC_in(PMINFO M1064_XPIXPLLCP
) != p
);
184 return (matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLM
) != m
||
185 matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLN
) != n
||
186 matroxfb_DAC_in(PMINFO DAC1064_XSYSPLLP
) != p
);
189 return (matroxfb_DAC_in(PMINFO M1064_XVIDPLLM
) != m
||
190 matroxfb_DAC_in(PMINFO M1064_XVIDPLLN
) != n
||
191 matroxfb_DAC_in(PMINFO M1064_XVIDPLLP
) != p
);
196 static inline int g450_isplllocked(CPMINFO
unsigned int regidx
) {
199 for (j
= 0; j
< 1000; j
++) {
200 if (matroxfb_DAC_in(PMINFO regidx
) & 0x40) {
204 for (i
= 0; i
< 100; i
++) {
205 r
+= matroxfb_DAC_in(PMINFO regidx
) & 0x40;
207 return r
>= (90 * 0x40);
209 /* udelay(1)... but DAC_in is much slower... */
214 static int g450_testpll(CPMINFO
unsigned int mnp
, unsigned int pll
) {
215 return g450_isplllocked(PMINFO
g450_setpll(PMINFO mnp
, pll
));
218 static void updatehwstate_clk(struct matrox_hw_state
* hw
, unsigned int mnp
, unsigned int pll
) {
221 hw
->DACclk
[3] = mnp
>> 16;
222 hw
->DACclk
[4] = mnp
>> 8;
228 void matroxfb_g450_setpll_cond(WPMINFO
unsigned int mnp
, unsigned int pll
) {
229 if (g450_cmppll(PMINFO mnp
, pll
)) {
230 g450_setpll(PMINFO mnp
, pll
);
234 static inline unsigned int g450_findworkingpll(WPMINFO
unsigned int pll
, unsigned int* mnparray
, unsigned int mnpcount
) {
235 unsigned int found
= 0;
237 unsigned int mnpfound
= mnparray
[0];
239 for (idx
= 0; idx
< mnpcount
; idx
++) {
240 unsigned int sarray
[3];
250 if ((mnp
& 0x38) != 0x38) {
255 while (sptr
>= sarray
) {
256 unsigned int mnp
= *sptr
--;
258 if (g450_testpll(PMINFO mnp
- 0x0300, pll
) &&
259 g450_testpll(PMINFO mnp
+ 0x0300, pll
) &&
260 g450_testpll(PMINFO mnp
- 0x0200, pll
) &&
261 g450_testpll(PMINFO mnp
+ 0x0200, pll
) &&
262 g450_testpll(PMINFO mnp
- 0x0100, pll
) &&
263 g450_testpll(PMINFO mnp
+ 0x0100, pll
)) {
264 if (g450_testpll(PMINFO mnp
, pll
)) {
267 } else if (!found
&& g450_testpll(PMINFO mnp
, pll
)) {
273 g450_setpll(PMINFO mnpfound
, pll
);
277 static void g450_addcache(struct matrox_pll_cache
* ci
, unsigned int mnp_key
, unsigned int mnp_value
) {
278 if (++ci
->valid
> ARRAY_SIZE(ci
->data
)) {
279 ci
->valid
= ARRAY_SIZE(ci
->data
);
281 memmove(ci
->data
+ 1, ci
->data
, (ci
->valid
- 1) * sizeof(*ci
->data
));
282 ci
->data
[0].mnp_key
= mnp_key
& G450_MNP_FREQBITS
;
283 ci
->data
[0].mnp_value
= mnp_value
;
286 static int g450_checkcache(WPMINFO
struct matrox_pll_cache
* ci
, unsigned int mnp_key
) {
289 mnp_key
&= G450_MNP_FREQBITS
;
290 for (i
= 0; i
< ci
->valid
; i
++) {
291 if (ci
->data
[i
].mnp_key
== mnp_key
) {
294 mnp
= ci
->data
[i
].mnp_value
;
296 memmove(ci
->data
+ 1, ci
->data
, i
* sizeof(*ci
->data
));
297 ci
->data
[0].mnp_key
= mnp_key
;
298 ci
->data
[0].mnp_value
= mnp
;
306 static int __g450_setclk(WPMINFO
unsigned int fout
, unsigned int pll
,
307 unsigned int* mnparray
, unsigned int* deltaarray
) {
308 unsigned int mnpcount
;
309 unsigned int pixel_vco
;
310 const struct matrox_pll_limits
* pi
;
311 struct matrox_pll_cache
* ci
;
319 u_int8_t tmp
, xpwrctrl
;
322 matroxfb_DAC_lock_irqsave(flags
);
324 xpwrctrl
= matroxfb_DAC_in(PMINFO M1064_XPWRCTRL
);
325 matroxfb_DAC_out(PMINFO M1064_XPWRCTRL
, xpwrctrl
& ~M1064_XPWRCTRL_PANELPDN
);
326 mga_outb(M_SEQ_INDEX
, M_SEQ1
);
327 mga_outb(M_SEQ_DATA
, mga_inb(M_SEQ_DATA
) | M_SEQ1_SCROFF
);
328 tmp
= matroxfb_DAC_in(PMINFO M1064_XPIXCLKCTRL
);
329 tmp
|= M1064_XPIXCLKCTRL_DIS
;
330 if (!(tmp
& M1064_XPIXCLKCTRL_PLL_UP
)) {
331 tmp
|= M1064_XPIXCLKCTRL_PLL_UP
;
333 matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL
, tmp
);
334 /* DVI PLL preferred for frequencies up to
335 panel link max, standard PLL otherwise */
336 if (fout
>= MINFO
->max_pixel_clock_panellink
)
339 M1064_XDVICLKCTRL_DVIDATAPATHSEL
|
340 M1064_XDVICLKCTRL_C1DVICLKSEL
|
341 M1064_XDVICLKCTRL_C1DVICLKEN
|
342 M1064_XDVICLKCTRL_DVILOOPCTL
|
343 M1064_XDVICLKCTRL_P1LOOPBWDTCTL
;
344 matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL
,tmp
);
345 matroxfb_DAC_out(PMINFO M1064_XPWRCTRL
,
348 matroxfb_DAC_unlock_irqrestore(flags
);
353 misc
= mga_inb(M_MISC_REG_READ
) & ~0x0C;
364 mga_outb(M_MISC_REG
, misc
);
366 pi
= &ACCESS_FBINFO(limits
.pixel
);
367 ci
= &ACCESS_FBINFO(cache
.pixel
);
373 pci_read_config_dword(ACCESS_FBINFO(pcidev
), PCI_OPTION_REG
, &opt
);
375 pci_write_config_dword(ACCESS_FBINFO(pcidev
), PCI_OPTION_REG
, opt
| 0x20);
378 pi
= &ACCESS_FBINFO(limits
.system
);
379 ci
= &ACCESS_FBINFO(cache
.system
);
387 matroxfb_DAC_lock_irqsave(flags
);
388 tmp
= matroxfb_DAC_in(PMINFO M1064_XPWRCTRL
);
390 matroxfb_DAC_out(PMINFO M1064_XPWRCTRL
, tmp
| 2);
393 mnp
= matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM
) << 16;
394 mnp
|= matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN
) << 8;
395 pixel_vco
= g450_mnp2vco(PMINFO mnp
);
396 matroxfb_DAC_unlock_irqrestore(flags
);
398 pi
= &ACCESS_FBINFO(limits
.video
);
399 ci
= &ACCESS_FBINFO(cache
.video
);
410 for(mnp
= g450_firstpll(PMINFO pi
, &xvco
, fout
); mnp
!= NO_MORE_MNP
; mnp
= g450_nextpll(PMINFO pi
, &xvco
, mnp
)) {
415 vco
= g450_mnp2vco(PMINFO mnp
);
417 if (pll
== M_VIDEO_PLL
) {
418 unsigned int big
, small
;
420 if (vco
< pixel_vco
) {
427 while (big
> small
) {
435 delta
= pll_freq_delta(fout
, g450_vco2f(mnp
, vco
));
436 for (idx
= mnpcount
; idx
> 0; idx
--) {
437 /* == is important; due to nextpll algorithm we get
438 sorted equally good frequencies from lower VCO
439 frequency to higher - with <= lowest wins, while
440 with < highest one wins */
441 if (delta
<= deltaarray
[idx
-1]) {
442 /* all else being equal except VCO,
443 * choose VCO not near (within 1/16th or so) VCOmin
444 * (freqs near VCOmin aren't as stable)
446 if (delta
== deltaarray
[idx
-1]
447 && vco
!= g450_mnp2vco(PMINFO mnparray
[idx
-1])
448 && vco
< (pi
->vcomin
* 17 / 16)) {
451 mnparray
[idx
] = mnparray
[idx
-1];
452 deltaarray
[idx
] = deltaarray
[idx
-1];
458 deltaarray
[idx
] = delta
;
462 /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
470 matroxfb_DAC_lock_irqsave(flags
);
471 mnp
= g450_checkcache(PMINFO ci
, mnparray
[0]);
472 if (mnp
!= NO_MORE_MNP
) {
473 matroxfb_g450_setpll_cond(PMINFO mnp
, pll
);
475 mnp
= g450_findworkingpll(PMINFO pll
, mnparray
, mnpcount
);
476 g450_addcache(ci
, mnparray
[0], mnp
);
478 updatehwstate_clk(&ACCESS_FBINFO(hw
), mnp
, pll
);
479 matroxfb_DAC_unlock_irqrestore(flags
);
484 /* It must be greater than number of possible PLL values.
485 * Currently there is 5(p) * 10(m) = 50 possible values. */
486 #define MNP_TABLE_SIZE 64
488 int matroxfb_g450_setclk(WPMINFO
unsigned int fout
, unsigned int pll
) {
491 arr
= kmalloc(sizeof(*arr
) * MNP_TABLE_SIZE
* 2, GFP_KERNEL
);
495 r
= __g450_setclk(PMINFO fout
, pll
, arr
, arr
+ MNP_TABLE_SIZE
);
502 EXPORT_SYMBOL(matroxfb_g450_setclk
);
503 EXPORT_SYMBOL(g450_mnp2f
);
504 EXPORT_SYMBOL(matroxfb_g450_setpll_cond
);
506 MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
507 MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
509 MODULE_LICENSE("GPL");