tvp3026clock.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "pci.h"
  5. #include "vga.h"
  6. #define SCALE(f) ((f)/10) /* could be /10 */
  7. static void
  8. init(Vga* vga, Ctlr* ctlr)
  9. {
  10. int f, k;
  11. ulong fmin, fvco, m, n, p, q;
  12. double z;
  13. if(ctlr->flag & Finit)
  14. return;
  15. if(vga->f[0] == 0)
  16. vga->f[0] = vga->mode->frequency;
  17. vga->misc &= ~0x0C;
  18. if(vga->f[0] == VgaFreq0){
  19. /* nothing to do */;
  20. }
  21. else if(vga->f[0] == VgaFreq1)
  22. vga->misc |= 0x04;
  23. else
  24. vga->misc |= 0x0C;
  25. /*
  26. * Look for values of n, d and p that give
  27. * the least error for
  28. * Fvco = 8*RefFreq*(65-m)/(65-n)
  29. * Fpll = Fvco/2**p
  30. * N and m are 6 bits, p is 2 bits. Constraints:
  31. * 110MHz <= Fvco <= 250MHz
  32. * 40 <= n <= 62
  33. * 1 <= m <= 62
  34. * 0 <= p <= 3
  35. * Should try to minimise n, m.
  36. *
  37. * There's nothing like brute force and ignorance.
  38. */
  39. fmin = vga->f[0];
  40. vga->m[0] = 0x15;
  41. vga->n[0] = 0x18;
  42. vga->p[0] = 3;
  43. for(m = 62; m > 0; m--){
  44. for(n = 62; n >= 40; n--){
  45. fvco = 8*SCALE(RefFreq)*(65-m)/(65-n);
  46. if(fvco < SCALE(110000000) || fvco > SCALE(250000000))
  47. continue;
  48. for(p = 0; p < 4; p++){
  49. f = SCALE(vga->f[0]) - (fvco>>p);
  50. if(f < 0)
  51. f = -f;
  52. if(f < fmin){
  53. fmin = f;
  54. vga->m[0] = m;
  55. vga->n[0] = n;
  56. vga->p[0] = p;
  57. }
  58. }
  59. }
  60. }
  61. /*
  62. * Now the loop clock:
  63. * m is fixed;
  64. * calculate n;
  65. * set z to the lower bound (110MHz) and calculate p and q.
  66. */
  67. vga->m[1] = 61;
  68. if(ctlr->flag & Uenhanced)
  69. k = 64/8;
  70. else
  71. k = 8/8;
  72. n = 65 - 4*k;
  73. fvco = (8*RefFreq*(65-vga->m[0]))/(65-vga->n[0]);
  74. vga->f[1] = fvco;
  75. z = 110.0*(65-n)/(4*(fvco/1000000.0)*k);
  76. if(z <= 16){
  77. for(p = 0; p < 4; p++){
  78. if(1<<(p+1) > z)
  79. break;
  80. }
  81. q = 0;
  82. }
  83. else{
  84. p = 3;
  85. q = (z - 16)/16 + 1;
  86. }
  87. vga->n[1] = n;
  88. vga->p[1] = p;
  89. vga->q[1] = q;
  90. ctlr->flag |= Finit;
  91. }
  92. Ctlr tvp3026clock = {
  93. "tvp3026clock", /* name */
  94. 0, /* snarf */
  95. 0, /* options */
  96. init, /* init */
  97. 0, /* load */
  98. 0, /* dump */
  99. };