Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
6.5 KiB

  1. /*++
  2. Copyright (c) 1990-1995 Microsoft Corporation
  3. Module Name:
  4. nnclk.c
  5. Abstract:
  6. This module contains the code to set the number nine clock.
  7. Environment:
  8. Kernel mode
  9. Revision History:
  10. --*/
  11. #include "s3.h"
  12. #if defined(ALLOC_PRAGMA)
  13. #pragma alloc_text(PAGE, calc_clock)
  14. #pragma alloc_text(PAGE, gcd)
  15. #pragma alloc_text(PAGE, set_clock)
  16. #endif
  17. #define PROM_WRITE_INDEX 0x51
  18. #define PROM_WRITE_BIT 0x80
  19. #define SSW_READ_ENBL_INDEX 0x55
  20. #define SSW_READ_ENBL_BIT 0x04
  21. #define SSW_READ_PORT 0x03C8
  22. #define SSW_WRITE_INDEX 0x5C
  23. #define LOCK_INDEX 0x39
  24. #define UNLOCK_PATTERN 0xA0
  25. #define LOCK_INDEX2 0x38
  26. #define UNLOCK_PATTERN2 0x48
  27. #define BIOS_32K_INDEX 0x31
  28. #define BIOS_32K_BIT 0x80
  29. #define MODE_CTRL_INDEX 0x42
  30. #define GOPA_FLSEL 0x40
  31. #define GOPB_ENABLE 0x80
  32. #define GOPB_SLED 0x40
  33. #define GOPB_FLSEL 0x20
  34. #define GOPB_BURN 0x10
  35. #undef MIN
  36. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  37. #undef MAX
  38. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  39. #define CRYSTAL_FREQUENCY (14318180 * 2)
  40. #define MIN_VCO_FREQUENCY 50000000
  41. #define MAX_NUMERATOR 130
  42. #define MAX_DENOMINATOR MIN(129, CRYSTAL_FREQUENCY / 400000)
  43. #define MIN_DENOMINATOR MAX(3, CRYSTAL_FREQUENCY / 2000000)
  44. /* Set up the softswitch write value */
  45. #define CLOCK(x) VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)(iotemp | (x)))
  46. #define C_DATA 2
  47. #define C_CLK 1
  48. #define C_BOTH 3
  49. #define C_NONE 0
  50. /****************************************************************************
  51. * calc_clock
  52. *
  53. * Usage: clock frequency [set]
  54. * frequency is specified in MHz
  55. *
  56. ***************************************************************************/
  57. long calc_clock(frequency, select)
  58. register long frequency; /* in Hz */
  59. int select;
  60. {
  61. register long index;
  62. long temp;
  63. long min_m, min_n, min_diff;
  64. long diff;
  65. int clock_m;
  66. int clock_n;
  67. int clock_p;
  68. min_diff = 0xFFFFFFF;
  69. min_n = 1;
  70. min_m = 1;
  71. /* Calculate 18 bit clock value */
  72. clock_p = 0;
  73. if (frequency < MIN_VCO_FREQUENCY)
  74. clock_p = 1;
  75. if (frequency < MIN_VCO_FREQUENCY / 2)
  76. clock_p = 2;
  77. if (frequency < MIN_VCO_FREQUENCY / 4)
  78. clock_p = 3;
  79. frequency <<= clock_p;
  80. for (clock_n = 4; clock_n <= MAX_NUMERATOR; clock_n++)
  81. {
  82. index = CRYSTAL_FREQUENCY / (frequency / clock_n);
  83. if (index > MAX_DENOMINATOR)
  84. index = MAX_DENOMINATOR;
  85. if (index < MIN_DENOMINATOR)
  86. index = MIN_DENOMINATOR;
  87. for (clock_m = index - 3; clock_m < index + 4; clock_m++)
  88. if (clock_m >= MIN_DENOMINATOR && clock_m <= MAX_DENOMINATOR)
  89. {
  90. diff = (CRYSTAL_FREQUENCY / clock_m) * clock_n - frequency;
  91. if (diff < 0)
  92. diff = -diff;
  93. if (min_m * gcd(clock_m, clock_n) / gcd(min_m, min_n) == clock_m &&
  94. min_n * gcd(clock_m, clock_n) / gcd(min_m, min_n) == clock_n)
  95. if (diff > min_diff)
  96. diff = min_diff;
  97. if (diff <= min_diff)
  98. {
  99. min_diff = diff;
  100. min_m = clock_m;
  101. min_n = clock_n;
  102. }
  103. }
  104. }
  105. clock_m = min_m;
  106. clock_n = min_n;
  107. /* Calculate the index */
  108. temp = (((CRYSTAL_FREQUENCY / 2) * clock_n) / clock_m) << 1;
  109. for (index = 0; vclk_range[index + 1] < temp && index < 15; index++)
  110. ;
  111. /* Pack the clock value for the frequency snthesizer */
  112. temp = (((long)clock_n - 3) << 11) + ((clock_m - 2) << 1)
  113. + (clock_p << 8) + (index << 18) + ((long)select << 22);
  114. return temp;
  115. }
  116. /******************************************************************************
  117. *
  118. *****************************************************************************/
  119. VOID set_clock(
  120. PHW_DEVICE_EXTENSION HwDeviceExtension,
  121. LONG clock_value) /* 7bits M, 7bits N, 2bits P */
  122. {
  123. register long index;
  124. register char iotemp;
  125. int select;
  126. select = (clock_value >> 22) & 3;
  127. /* Unlock the S3 registers */
  128. VideoPortWritePortUchar(CRT_ADDRESS_REG, LOCK_INDEX);
  129. VideoPortWritePortUchar(CRT_DATA_REG, UNLOCK_PATTERN);
  130. /* Shut off screen */
  131. VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x01);
  132. iotemp = VideoPortReadPortUchar(SEQ_DATA_REG);
  133. VideoPortWritePortUchar(SEQ_DATA_REG, (UCHAR)(iotemp | 0x20));
  134. /* set clock input to 11 binary */
  135. iotemp = VideoPortReadPortUchar(MISC_OUTPUT_REG_READ);
  136. VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)(iotemp | 0x0C));
  137. VideoPortWritePortUchar(CRT_ADDRESS_REG, SSW_WRITE_INDEX);
  138. VideoPortWritePortUchar(CRT_DATA_REG, 0);
  139. VideoPortWritePortUchar(CRT_ADDRESS_REG, MODE_CTRL_INDEX);
  140. iotemp = VideoPortReadPortUchar(CRT_DATA_REG) & 0xF0;
  141. /* Program the IC Designs 2061A frequency generator */
  142. CLOCK(C_NONE);
  143. /* Unlock sequence */
  144. CLOCK(C_DATA);
  145. for (index = 0; index < 6; index++)
  146. {
  147. CLOCK(C_BOTH);
  148. CLOCK(C_DATA);
  149. }
  150. CLOCK(C_NONE);
  151. CLOCK(C_CLK);
  152. CLOCK(C_NONE);
  153. CLOCK(C_CLK);
  154. /* Program the 24 bit value into REG0 */
  155. for (index = 0; index < 24; index++)
  156. {
  157. /* Clock in the next bit */
  158. clock_value >>= 1;
  159. if (clock_value & 1)
  160. {
  161. CLOCK(C_CLK);
  162. CLOCK(C_NONE);
  163. CLOCK(C_DATA);
  164. CLOCK(C_BOTH);
  165. }
  166. else
  167. {
  168. CLOCK(C_BOTH);
  169. CLOCK(C_DATA);
  170. CLOCK(C_NONE);
  171. CLOCK(C_CLK);
  172. }
  173. }
  174. CLOCK(C_BOTH);
  175. CLOCK(C_DATA);
  176. CLOCK(C_BOTH);
  177. /* If necessary, reprogram other ICD2061A registers to defaults */
  178. /* Select the CLOCK in the frequency synthesizer */
  179. CLOCK(C_NONE | select);
  180. /* Turn screen back on */
  181. VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x01);
  182. iotemp = VideoPortReadPortUchar(SEQ_DATA_REG);
  183. VideoPortWritePortUchar(SEQ_DATA_REG, (UCHAR) (iotemp & 0xDF));
  184. }
  185. /******************************************************************************
  186. * Number theoretic function - GCD (Greatest Common Divisor)
  187. *****************************************************************************/
  188. long gcd(a, b)
  189. register long a, b;
  190. {
  191. register long c = a % b;
  192. while (c)
  193. a = b, b = c, c = a % b;
  194. return b;
  195. }