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 matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL
, 0);
335 matroxfb_DAC_out(PMINFO M1064_XPWRCTRL
, xpwrctrl
);
337 matroxfb_DAC_unlock_irqrestore(flags
);
342 misc
= mga_inb(M_MISC_REG_READ
) & ~0x0C;
353 mga_outb(M_MISC_REG
, misc
);
355 pi
= &ACCESS_FBINFO(limits
.pixel
);
356 ci
= &ACCESS_FBINFO(cache
.pixel
);
362 pci_read_config_dword(ACCESS_FBINFO(pcidev
), PCI_OPTION_REG
, &opt
);
364 pci_write_config_dword(ACCESS_FBINFO(pcidev
), PCI_OPTION_REG
, opt
| 0x20);
367 pi
= &ACCESS_FBINFO(limits
.system
);
368 ci
= &ACCESS_FBINFO(cache
.system
);
376 matroxfb_DAC_lock_irqsave(flags
);
377 tmp
= matroxfb_DAC_in(PMINFO M1064_XPWRCTRL
);
379 matroxfb_DAC_out(PMINFO M1064_XPWRCTRL
, tmp
| 2);
382 mnp
= matroxfb_DAC_in(PMINFO M1064_XPIXPLLCM
) << 16;
383 mnp
|= matroxfb_DAC_in(PMINFO M1064_XPIXPLLCN
) << 8;
384 pixel_vco
= g450_mnp2vco(PMINFO mnp
);
385 matroxfb_DAC_unlock_irqrestore(flags
);
387 pi
= &ACCESS_FBINFO(limits
.video
);
388 ci
= &ACCESS_FBINFO(cache
.video
);
399 for(mnp
= g450_firstpll(PMINFO pi
, &xvco
, fout
); mnp
!= NO_MORE_MNP
; mnp
= g450_nextpll(PMINFO pi
, &xvco
, mnp
)) {
404 vco
= g450_mnp2vco(PMINFO mnp
);
406 if (pll
== M_VIDEO_PLL
) {
407 unsigned int big
, small
;
409 if (vco
< pixel_vco
) {
416 while (big
> small
) {
424 delta
= pll_freq_delta(fout
, g450_vco2f(mnp
, vco
));
425 for (idx
= mnpcount
; idx
> 0; idx
--) {
426 /* == is important; due to nextpll algorithm we get
427 sorted equally good frequencies from lower VCO
428 frequency to higher - with <= lowest wins, while
429 with < highest one wins */
430 if (delta
<= deltaarray
[idx
-1]) {
431 /* all else being equal except VCO,
432 * choose VCO not near (within 1/16th or so) VCOmin
433 * (freqs near VCOmin aren't as stable)
435 if (delta
== deltaarray
[idx
-1]
436 && vco
!= g450_mnp2vco(PMINFO mnparray
[idx
-1])
437 && vco
< (pi
->vcomin
* 17 / 16)) {
440 mnparray
[idx
] = mnparray
[idx
-1];
441 deltaarray
[idx
] = deltaarray
[idx
-1];
447 deltaarray
[idx
] = delta
;
451 /* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
459 matroxfb_DAC_lock_irqsave(flags
);
460 mnp
= g450_checkcache(PMINFO ci
, mnparray
[0]);
461 if (mnp
!= NO_MORE_MNP
) {
462 matroxfb_g450_setpll_cond(PMINFO mnp
, pll
);
464 mnp
= g450_findworkingpll(PMINFO pll
, mnparray
, mnpcount
);
465 g450_addcache(ci
, mnparray
[0], mnp
);
467 updatehwstate_clk(&ACCESS_FBINFO(hw
), mnp
, pll
);
468 matroxfb_DAC_unlock_irqrestore(flags
);
473 /* It must be greater than number of possible PLL values.
474 * Currently there is 5(p) * 10(m) = 50 possible values. */
475 #define MNP_TABLE_SIZE 64
477 int matroxfb_g450_setclk(WPMINFO
unsigned int fout
, unsigned int pll
) {
480 arr
= kmalloc(sizeof(*arr
) * MNP_TABLE_SIZE
* 2, GFP_KERNEL
);
484 r
= __g450_setclk(PMINFO fout
, pll
, arr
, arr
+ MNP_TABLE_SIZE
);
491 EXPORT_SYMBOL(matroxfb_g450_setclk
);
492 EXPORT_SYMBOL(g450_mnp2f
);
493 EXPORT_SYMBOL(matroxfb_g450_setpll_cond
);
495 MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
496 MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
498 MODULE_LICENSE("GPL");