icd2061a.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * IC Designs ICD2061A Dual Programmable Graphics Clock Generator.
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <bio.h>
  7. #include "pci.h"
  8. #include "vga.h"
  9. enum {
  10. Prescale = 2, /* P counter prescale (default) */
  11. NIndex = 14, /* number of index field values */
  12. };
  13. /*
  14. * For an index value of x, the appropriate VCO range
  15. * is >= index[x] && <= index[x+1]. The higher index is
  16. * prefered if VCO is on a boundary.
  17. */
  18. static ulong index[NIndex] = {
  19. 50000000,
  20. 51000000,
  21. 53200000,
  22. 58500000,
  23. 60700000,
  24. 64400000,
  25. 66800000,
  26. 73500000,
  27. 75600000,
  28. 80900000,
  29. 83200000,
  30. 91500000,
  31. 100000000,
  32. 120000000,
  33. };
  34. static void
  35. init(Vga* vga, Ctlr* ctlr)
  36. {
  37. int f;
  38. ulong d, dmax, fmin, n;
  39. if(ctlr->flag & Finit)
  40. return;
  41. if(vga->f[0] == 0)
  42. vga->f[0] = vga->mode->frequency;
  43. if(vga->mode->z > 8)
  44. error("depth %d not supported\n", vga->mode->z);
  45. /*
  46. * Post-VCO divisor. Constraint:
  47. * 50MHz <= vga->f <= 120MHz
  48. */
  49. for(vga->p[0] = 0; vga->f[0] <= 50000000; vga->p[0]++)
  50. vga->f[0] <<= 1;
  51. /*
  52. * Determine index.
  53. */
  54. for(vga->i[0] = NIndex-1; vga->f[0] < index[vga->i[0]] && vga->i[0]; vga->i[0]--)
  55. ;
  56. /*
  57. * Denominator. Constraints:
  58. * 200KHz <= RefFreq/d <= 1MHz
  59. * and
  60. * 3 <= d <= 129
  61. *
  62. * Numerator. Constraint:
  63. * 4 <= n <= 130
  64. */
  65. d = RefFreq/1000000 > 3 ? RefFreq/1000000: 3;
  66. dmax = RefFreq/200000 < 129 ? RefFreq/200000: 129;
  67. /*
  68. * Now look for values of p and q that give
  69. * the least error for
  70. * vga->f = (Prescale*RefFreq*n/d);
  71. */
  72. vga->d[0] = d;
  73. vga->n[0] = 4;
  74. for(fmin = vga->f[0]; d <= dmax; d++){
  75. for(n = 4; n <= 130; n++){
  76. f = vga->f[0] - (Prescale*RefFreq*n/d);
  77. if(f < 0)
  78. f = -f;
  79. if(f < fmin){
  80. fmin = f;
  81. vga->d[0] = d;
  82. vga->n[0] = n;
  83. }
  84. }
  85. }
  86. /*
  87. * The serial word to be loaded into the icd2061a is
  88. * (2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d
  89. * Always select ICD2061A REG2.
  90. */
  91. vga->f[0] = (Prescale*RefFreq*vga->n[0]/vga->d[0]);
  92. vga->d[0] -= 2;
  93. vga->n[0] -= 3;
  94. ctlr->flag |= Finit;
  95. }
  96. Ctlr icd2061a = {
  97. "icd2061a",
  98. 0, /* snarf */
  99. 0, /* options */
  100. init, /* init */
  101. 0, /* load */
  102. 0, /* dump */
  103. };