1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5/* All drivers should typically include these */
6#include "xf86.h"
7#include "xf86_OSproc.h"
8
9/* Drivers that need to access the PCI config space directly need this */
10#include "xf86Pci.h"
11
12#include "mga_reg.h"
13#include "mga.h"
14
15#define MNP_TABLE_SIZE 64
16#define CLKSEL_MGA     0x0c
17#define PLLLOCK        0x40
18
19static CARD32 G450ApplyPFactor(ScrnInfoPtr pScrn, CARD8 ucP, CARD32 *pulFIn)
20{
21   if(!(ucP & 0x40))
22   {
23      *pulFIn = *pulFIn / (2L << (ucP & 3));
24   }
25
26   return TRUE;
27}
28
29
30static CARD32 G450RemovePFactor(ScrnInfoPtr pScrn, CARD8 ucP, CARD32 *pulFIn)
31{
32   if(!(ucP & 0x40))
33   {
34      *pulFIn = *pulFIn * (2L << (ucP & 3));
35   }
36
37   return TRUE;
38}
39
40
41static CARD32 G450CalculVCO(ScrnInfoPtr pScrn, CARD32 ulMNP, CARD32 *pulF)
42{
43   CARD8 ucM, ucN;
44
45   ucM = (CARD8)((ulMNP >> 16) & 0xff);
46   ucN = (CARD8)((ulMNP >>  8) & 0xff);
47
48   *pulF = (27000 * (2 * (ucN + 2)) + ((ucM + 1) >> 1)) / (ucM + 1);
49
50   return TRUE;
51}
52
53
54static CARD32 G450CalculDeltaFreq(ScrnInfoPtr pScrn, CARD32 ulF1,
55                                  CARD32 ulF2, CARD32 *pulDelta)
56{
57   if(ulF2 < ulF1)
58   {
59      *pulDelta = ((ulF1 - ulF2) * 1000) / ulF1;
60   }
61   else
62   {
63      *pulDelta = ((ulF2 - ulF1) * 1000) / ulF1;
64   }
65
66   return TRUE;
67}
68
69
70
71
72static CARD32 G450FindNextPLLParam(ScrnInfoPtr pScrn, CARD32 ulFout,
73                                   CARD32 *pulPLLMNP)
74{
75   CARD8 ucM, ucN, ucP, ucS;
76   CARD32 ulVCO, ulVCOMin;
77
78   ucM = (CARD8)((*pulPLLMNP >> 16) & 0xff);
79   ucN = (CARD8)((*pulPLLMNP >>  8) & 0xff);
80   ucP = (CARD8)(*pulPLLMNP &  0x43);
81
82   ulVCOMin = 256000;
83
84   if(ulVCOMin >= (255L * 8000))
85   {
86      ulVCOMin = 230000;
87   }
88
89   if((ucM == 9) && (ucP & 0x40))
90   {
91      *pulPLLMNP = 0xffffffff;
92   } else if (ucM == 9)
93   {
94      if(ucP)
95      {
96         ucP--;
97      }
98      else
99      {
100         ucP = 0x40;
101      }
102      ucM = 0;
103   }
104   else
105   {
106      ucM++;
107   }
108
109   ulVCO = ulFout;
110
111   G450RemovePFactor(pScrn, ucP, &ulVCO);
112
113   if(ulVCO < ulVCOMin)
114   {
115      *pulPLLMNP = 0xffffffff;
116   }
117
118   if(*pulPLLMNP != 0xffffffff)
119   {
120      ucN = (CARD8)(((ulVCO * (ucM+1) + 27000)/(27000 * 2)) - 2);
121
122      ucS = 5;
123      if(ulVCO < 1300000) ucS = 4;
124      if(ulVCO < 1100000) ucS = 3;
125      if(ulVCO <  900000) ucS = 2;
126      if(ulVCO <  700000) ucS = 1;
127      if(ulVCO <  550000) ucS = 0;
128
129      ucP |= (CARD8)(ucS << 3);
130
131      *pulPLLMNP &= 0xff000000;
132      *pulPLLMNP |= (CARD32)ucM << 16;
133      *pulPLLMNP |= (CARD32)ucN << 8;
134      *pulPLLMNP |= (CARD32)ucP;
135
136#ifdef DEBUG
137      ErrorF("FINS_S: VCO = %d, S = %02X, *pulPLLMNP = %08X\n", (unsigned)ulVCO, (unsigned)ucS, (unsigned)*pulPLLMNP);
138#endif
139  }
140
141   return TRUE;
142}
143
144
145static CARD32 G450FindFirstPLLParam(ScrnInfoPtr pScrn, CARD32 ulFout,
146                                    CARD32 *pulPLLMNP)
147{
148   CARD8 ucP;
149   CARD32 ulVCO;
150   CARD32 ulVCOMax;
151
152   /* Default value */
153   ulVCOMax = 1300000;
154
155   if(ulFout > (ulVCOMax/2))
156   {
157      ucP = 0x40;
158      ulVCO = ulFout;
159   }
160   else
161   {
162      ucP = 3;
163      ulVCO = ulFout;
164      G450RemovePFactor(pScrn, ucP, &ulVCO);
165      while(ucP && (ulVCO > ulVCOMax))
166      {
167         ucP--;
168         ulVCO = ulFout;
169         G450RemovePFactor(pScrn, ucP, &ulVCO);
170      }
171   }
172
173   if(ulVCO > ulVCOMax)
174   {
175      *pulPLLMNP = 0xffffffff;
176   }
177   else
178   {
179      /* Pixel clock: 1 */
180      *pulPLLMNP = (1 << 24) + 0xff0000 + ucP;
181      G450FindNextPLLParam(pScrn, ulFout, pulPLLMNP);
182   }
183
184   return TRUE;
185
186}
187
188
189static CARD32 G450WriteMNP(ScrnInfoPtr pScrn, CARD32 ulMNP)
190{
191   MGAPtr pMga = MGAPTR(pScrn);
192
193   if (!pMga->SecondCrtc) {
194      outMGAdac(MGA1064_PIX_PLLC_M, (CARD8)(ulMNP >> 16));
195      outMGAdac(MGA1064_PIX_PLLC_N, (CARD8)(ulMNP >>  8));
196      outMGAdac(MGA1064_PIX_PLLC_P, (CARD8) ulMNP);
197   } else {
198      outMGAdac(MGA1064_VID_PLL_M, (CARD8)(ulMNP >> 16));
199      outMGAdac(MGA1064_VID_PLL_N, (CARD8)(ulMNP >> 8));
200      outMGAdac(MGA1064_VID_PLL_P, (CARD8) ulMNP);
201   }
202   return TRUE;
203}
204
205static CARD32 G450ReadMNP(ScrnInfoPtr pScrn)
206{
207   MGAPtr pMga = MGAPTR(pScrn);
208   CARD32 ret = 0;
209
210   if (!pMga->SecondCrtc) {
211      ret = (CARD8)inMGAdac(MGA1064_PIX_PLLC_M) << 16;
212      ret |= (CARD8)inMGAdac(MGA1064_PIX_PLLC_N) << 8;
213      ret |= (CARD8)inMGAdac(MGA1064_PIX_PLLC_P);
214   } else {
215      ret = (CARD8)inMGAdac(MGA1064_VID_PLL_M) << 16;
216      ret |= (CARD8)inMGAdac(MGA1064_VID_PLL_N) << 8;
217      ret |= (CARD8)inMGAdac(MGA1064_VID_PLL_P);
218   }
219   return ret;
220}
221
222
223static CARD32 G450CompareMNP(ScrnInfoPtr pScrn, CARD32 ulFout, CARD32 ulMNP1,
224                      CARD32 ulMNP2, long *pulResult)
225{
226   CARD32 ulFreq, ulDelta1, ulDelta2;
227
228   G450CalculVCO(pScrn, ulMNP1, &ulFreq);
229   G450ApplyPFactor(pScrn, (CARD8) ulMNP1, &ulFreq);
230   G450CalculDeltaFreq(pScrn, ulFout, ulFreq, &ulDelta1);
231
232   G450CalculVCO(pScrn, ulMNP2, &ulFreq);
233   G450ApplyPFactor(pScrn, (CARD8) ulMNP2, &ulFreq);
234   G450CalculDeltaFreq(pScrn, ulFout, ulFreq, &ulDelta2);
235
236   if(ulDelta1 < ulDelta2)
237   {
238      *pulResult = -1;
239   }
240   else if(ulDelta1 > ulDelta2)
241   {
242      *pulResult = 1;
243   }
244   else
245   {
246      *pulResult = 0;
247   }
248
249   if((ulDelta1 <= 5) && (ulDelta2 <= 5))
250   {
251      if((ulMNP1 & 0xff0000) < (ulMNP2 & 0xff0000))
252      {
253         *pulResult = -1;
254      }
255      else if((ulMNP1 & 0xff0000) > (ulMNP2 & 0xff0000))
256      {
257         *pulResult = 1;
258      }
259   }
260
261   return TRUE;
262}
263
264
265static CARD32 G450IsPllLocked(ScrnInfoPtr pScrn, Bool *lpbLocked)
266{
267   CARD32 ulFallBackCounter, ulLockCount, ulCount;
268   CARD8  ucPLLStatus;
269
270   MGAPtr pMga = MGAPTR(pScrn);
271
272   if (!pMga->SecondCrtc)
273      OUTREG8(0x3c00, MGA1064_PIX_PLL_STAT);
274   else
275      OUTREG8(0x3c00, MGA1064_VID_PLL_STAT);
276
277   ulFallBackCounter = 0;
278
279   do
280   {
281      ucPLLStatus = INREG8(0x3c0a);
282      ulFallBackCounter++;
283   } while(!(ucPLLStatus & PLLLOCK) && (ulFallBackCounter < 1000));
284
285   ulLockCount = 0;
286   if(ulFallBackCounter < 1000)
287   {
288      for(ulCount = 0; ulCount < 100; ulCount++)
289      {
290         ucPLLStatus = INREG8(0x3c0a);
291         if(ucPLLStatus & PLLLOCK)
292         {
293            ulLockCount++;
294         }
295      }
296   }
297
298   *lpbLocked = ulLockCount >= 90;
299
300   return TRUE;
301}
302
303
304double MGAG450SetPLLFreq(ScrnInfoPtr pScrn, long f_out)
305{
306   Bool bFoundValidPLL;
307   Bool bLocked;
308   CARD8  ucMisc, ucSIndex, ucSTable[4];
309   CARD32 ulMaxIndex;
310   CARD32 ulMNP;
311   CARD32 ulMNPTable[MNP_TABLE_SIZE];
312   CARD32 ulIndex;
313   CARD32 ulTryMNP;
314   long lCompareResult;
315   MGAPtr pMga = MGAPTR(pScrn);
316
317#ifdef DEBUG
318   xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Restoring PLLClk = %ld\n", f_out);
319#endif
320   G450FindFirstPLLParam(pScrn, f_out, &ulMNP);
321   ulMNPTable[0] = ulMNP;
322   G450FindNextPLLParam(pScrn, f_out, &ulMNP);
323   ulMaxIndex = 1;
324   while(ulMNP != 0xffffffff)
325   {
326      int ulIndex;
327      Bool bSkipValue;
328
329      bSkipValue = FALSE;
330      if(ulMaxIndex == MNP_TABLE_SIZE)
331      {
332         G450CompareMNP(pScrn, f_out, ulMNP, ulMNPTable[MNP_TABLE_SIZE - 1],
333                        &lCompareResult);
334
335         if(lCompareResult > 0)
336         {
337            bSkipValue = TRUE;
338         }
339         else
340         {
341            ulMaxIndex--;
342         }
343      }
344
345      if(!bSkipValue)
346      {
347         for(ulIndex = ulMaxIndex; !bSkipValue && (ulIndex > 0); ulIndex--)
348         {
349            G450CompareMNP(pScrn, f_out, ulMNP, ulMNPTable[ulIndex - 1],
350                           &lCompareResult);
351
352            if(lCompareResult < 0)
353            {
354               ulMNPTable[ulIndex] = ulMNPTable[ulIndex - 1];
355            }
356            else
357            {
358               break;
359            }
360         }
361         ulMNPTable[ulIndex] = ulMNP;
362         ulMaxIndex++;
363      }
364
365      G450FindNextPLLParam(pScrn, f_out, &ulMNP);
366   }
367
368   bFoundValidPLL = FALSE;
369   ulMNP = 0;
370
371   /* For pixel pll */
372   if (!pMga->SecondCrtc) {
373       ucMisc = INREG8(0x1FCC);
374       OUTREG8(0x1fc2, (CARD8)(ucMisc | CLKSEL_MGA));
375   }
376
377   for(ulIndex = 0; !bFoundValidPLL && (ulIndex < ulMaxIndex); ulIndex++)
378   {
379       ulTryMNP = ulMNPTable[ulIndex];
380
381       ucSTable[3] = 0xff;
382       ucSTable[2] = 0xff;
383       ucSTable[0] = (CARD8) (ulTryMNP & 0x38);
384
385       if (ucSTable[0] != 0)  {
386	   ucSTable[1] = ucSTable[0] - 8;
387	   if (ucSTable[0] != 0x38) {
388	       ucSTable[2] = ucSTable[0] + 8;
389	   }
390       } else {
391	   ucSTable[1] = 8;
392       }
393
394       for(ucSIndex = 0; !bFoundValidPLL && (ucSTable[ucSIndex] != 0xff);
395	   ucSIndex++) {
396	    ulTryMNP &= 0xffffffc7;
397	    ulTryMNP |= (CARD32)ucSTable[ucSIndex];
398
399         bLocked = TRUE;
400         if((ulMNPTable[ulIndex] & 0xff00) < 0x300 ||
401            (ulMNPTable[ulIndex] & 0xff00) > 0x7a00)
402         {
403            bLocked = FALSE;
404         }
405
406         if(bLocked)
407         {
408            G450WriteMNP(pScrn, ulTryMNP - 0x300);
409            G450IsPllLocked(pScrn, &bLocked);
410         }
411
412         if(bLocked)
413         {
414            G450WriteMNP(pScrn, ulTryMNP + 0x300);
415            G450IsPllLocked(pScrn, &bLocked);
416         }
417
418         if(bLocked)
419         {
420            G450WriteMNP(pScrn, ulTryMNP - 0x200);
421            G450IsPllLocked(pScrn, &bLocked);
422         }
423
424         if(bLocked)
425         {
426            G450WriteMNP(pScrn, ulTryMNP + 0x200);
427            G450IsPllLocked(pScrn, &bLocked);
428         }
429
430         if(bLocked)
431         {
432            G450WriteMNP(pScrn, ulTryMNP - 0x100);
433            G450IsPllLocked(pScrn, &bLocked);
434         }
435
436         if(bLocked)
437         {
438            G450WriteMNP(pScrn, ulTryMNP + 0x100);
439            G450IsPllLocked(pScrn, &bLocked);
440         }
441
442         if(bLocked)
443         {
444            G450WriteMNP(pScrn, ulTryMNP);
445            G450IsPllLocked(pScrn, &bLocked);
446         }
447         else if(!ulMNP)
448         {
449            G450WriteMNP(pScrn, ulTryMNP);
450            G450IsPllLocked(pScrn, &bLocked);
451            if(bLocked)
452            {
453               ulMNP = ulMNPTable[ulIndex];
454            }
455            bLocked = FALSE;
456         }
457
458         if(bLocked)
459         {
460            bFoundValidPLL = TRUE;
461         }
462      }
463   }
464
465   if(!bFoundValidPLL)
466   {
467      if(ulMNP)
468      {
469         G450WriteMNP(pScrn, ulMNP);
470      }
471      else
472      {
473         G450WriteMNP(pScrn, ulMNPTable[0]);
474      }
475   }
476
477   return TRUE;
478}
479
480long
481MGAG450SavePLLFreq(ScrnInfoPtr pScrn)
482{
483    CARD32 ulMNP = G450ReadMNP(pScrn);
484    CARD8  ucP;
485    CARD32 freq;
486
487    G450CalculVCO(pScrn, ulMNP, &freq);
488    ucP = (CARD8)(ulMNP & 0x03);
489    G450ApplyPFactor(pScrn, ucP, &freq);
490
491#ifdef DEBUG
492    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Saved PLLClk = %u\n", (unsigned)freq);
493#endif
494    return freq;
495}
496
497#ifdef DEBUG
498void
499MGAG450PrintPLL(ScrnInfoPtr pScrn)
500{
501    CARD32 ulMNP = G450ReadMNP(pScrn);
502    CARD8  ucP;
503    CARD32 freq;
504
505    G450CalculVCO(pScrn, ulMNP, &freq);
506    ucP = (CARD8)(ulMNP & 0x03);
507    G450ApplyPFactor(pScrn, ucP, &freq);
508
509    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"MGAGClock = %u -- MNP = 0x%x\n",
510	       (unsigned)freq, (unsigned)ulMNP);
511}
512#endif
513