|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1990-1993 Microsoft Corporation
4:
5: Module Name:
6:
7: s3.c
8:
9: Abstract:
10:
11: This module contains the code to set the number nine clock.
12:
13: Environment:
14:
15: Kernel mode
16:
17: Revision History:
18:
19: --*/
20:
21: #include "s3.h"
22:
23: #define PROM_WRITE_INDEX 0x51
24: #define PROM_WRITE_BIT 0x80
25: #define SSW_READ_ENBL_INDEX 0x55
26: #define SSW_READ_ENBL_BIT 0x04
27: #define SSW_READ_PORT 0x03C8
28: #define SSW_WRITE_INDEX 0x5C
29: #define LOCK_INDEX 0x39
30: #define UNLOCK_PATTERN 0xA0
31: #define LOCK_INDEX2 0x38
32: #define UNLOCK_PATTERN2 0x48
33: #define BIOS_32K_INDEX 0x31
34: #define BIOS_32K_BIT 0x80
35: #define MODE_CTRL_INDEX 0x42
36:
37: #define GOPA_FLSEL 0x40
38: #define GOPB_ENABLE 0x80
39: #define GOPB_SLED 0x40
40: #define GOPB_FLSEL 0x20
41: #define GOPB_BURN 0x10
42:
43:
44: long calc_clock(long, int);
45: long gcd(long, long);
46: VOID set_clock(
47: PHW_DEVICE_EXTENSION HwDeviceExtension,
48: LONG clock_value);
49:
50:
51: #undef MIN
52: #define MIN(a, b) (((a) < (b)) ? (a) : (b))
53: #undef MAX
54: #define MAX(a, b) (((a) > (b)) ? (a) : (b))
55: #define CRYSTAL_FREQUENCY (14318180 * 2)
56: #define MIN_VCO_FREQUENCY 50000000
57: #define MAX_POST_SCALE 285000000
58: #define MAX_NUMERATOR 130
59: #define MAX_DENOMINATOR MIN(129, CRYSTAL_FREQUENCY / 400000)
60: #define MIN_DENOMINATOR MAX(3, CRYSTAL_FREQUENCY / 2000000)
61:
62: /* Set up the softswitch write value */
63:
64: #define CLOCK(x) VideoPortWritePortUchar(CRT_DATA_REG, (UCHAR)(iotemp | (x)))
65: #define C_DATA 2
66: #define C_CLK 1
67: #define C_BOTH 3
68: #define C_NONE 0
69:
70: /* Index register frequency ranges for ICD2061A chip */
71:
72: static long vclk_range[16] = {
73: 0, /* should be MIN_VCO_FREQUENCY, but that causes problems. */
74: 51000000,
75: 53200000,
76: 58500000,
77: 60700000,
78: 64400000,
79: 66800000,
80: 73500000,
81: 75600000,
82: 80900000,
83: 83200000,
84: 91500000,
85: 100000000,
86: 120000000,
87: MAX_POST_SCALE,
88: 0,
89: };
90:
91: /****************************************************************************
92: * calc_clock
93: *
94: * Usage: clock frequency [set]
95: * frequency is specified in MHz
96: *
97: ***************************************************************************/
98: long calc_clock(frequency, select)
99:
100: register long frequency; /* in Hz */
101: int select;
102: {
103: register long index;
104: long temp;
105: long min_m, min_n, min_diff;
106: long diff;
107:
108: int clock_m;
109: int clock_n;
110: int clock_p;
111:
112: min_diff = 0xFFFFFFF;
113: min_n = 1;
114: min_m = 1;
115:
116: /* Calculate 18 bit clock value */
117:
118: clock_p = 0;
119: if (frequency < MIN_VCO_FREQUENCY)
120: clock_p = 1;
121: if (frequency < MIN_VCO_FREQUENCY / 2)
122: clock_p = 2;
123: if (frequency < MIN_VCO_FREQUENCY / 4)
124: clock_p = 3;
125:
126: frequency <<= clock_p;
127:
128: for (clock_n = 4; clock_n <= MAX_NUMERATOR; clock_n++)
129: {
130: index = CRYSTAL_FREQUENCY / (frequency / clock_n);
131:
132: if (index > MAX_DENOMINATOR)
133: index = MAX_DENOMINATOR;
134: if (index < MIN_DENOMINATOR)
135: index = MIN_DENOMINATOR;
136:
137: for (clock_m = index - 3; clock_m < index + 4; clock_m++)
138: if (clock_m >= MIN_DENOMINATOR && clock_m <= MAX_DENOMINATOR)
139: {
140: diff = (CRYSTAL_FREQUENCY / clock_m) * clock_n - frequency;
141:
142: if (diff < 0)
143: diff = -diff;
144:
145: if (min_m * gcd(clock_m, clock_n) / gcd(min_m, min_n) == clock_m &&
146: min_n * gcd(clock_m, clock_n) / gcd(min_m, min_n) == clock_n)
147:
148: if (diff > min_diff)
149: diff = min_diff;
150:
151: if (diff <= min_diff)
152: {
153: min_diff = diff;
154: min_m = clock_m;
155: min_n = clock_n;
156: }
157: }
158: }
159:
160: clock_m = min_m;
161: clock_n = min_n;
162:
163: /* Calculate the index */
164:
165: temp = (((CRYSTAL_FREQUENCY / 2) * clock_n) / clock_m) << 1;
166: for (index = 0; vclk_range[index + 1] < temp && index < 15; index++)
167: ;
168:
169: /* Pack the clock value for the frequency snthesizer */
170:
171: temp = (((long)clock_n - 3) << 11) + ((clock_m - 2) << 1)
172: + (clock_p << 8) + (index << 18) + ((long)select << 22);
173:
174: return temp;
175:
176: }
177:
178: /******************************************************************************
179: *
180: *****************************************************************************/
181: VOID set_clock(
182: PHW_DEVICE_EXTENSION HwDeviceExtension,
183: LONG clock_value) /* 7bits M, 7bits N, 2bits P */
184: {
185: register long index;
186: register char iotemp;
187: int select;
188:
189: select = (clock_value >> 22) & 3;
190:
191: /* Unlock the S3 registers */
192:
193: VideoPortWritePortUchar(CRT_ADDRESS_REG, LOCK_INDEX);
194: VideoPortWritePortUchar(CRT_DATA_REG, UNLOCK_PATTERN);
195:
196: /* Shut off screen */
197:
198: VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x01);
199: iotemp = VideoPortReadPortUchar(SEQ_DATA_REG);
200: VideoPortWritePortUchar(SEQ_DATA_REG, (UCHAR)(iotemp | 0x20));
201:
202: /* set clock input to 11 binary */
203:
204: iotemp = VideoPortReadPortUchar(MISC_OUTPUT_REG_READ);
205: VideoPortWritePortUchar(MISC_OUTPUT_REG_WRITE, (UCHAR)(iotemp | 0x0C));
206:
207: VideoPortWritePortUchar(CRT_ADDRESS_REG, SSW_WRITE_INDEX);
208: VideoPortWritePortUchar(CRT_DATA_REG, 0);
209:
210: VideoPortWritePortUchar(CRT_ADDRESS_REG, MODE_CTRL_INDEX);
211: iotemp = VideoPortReadPortUchar(CRT_DATA_REG) & 0xF0;
212:
213:
214: /* Program the IC Designs 2061A frequency generator */
215:
216: CLOCK(C_NONE);
217:
218: /* Unlock sequence */
219:
220: CLOCK(C_DATA);
221: for (index = 0; index < 6; index++)
222: {
223: CLOCK(C_BOTH);
224: CLOCK(C_DATA);
225: }
226: CLOCK(C_NONE);
227: CLOCK(C_CLK);
228: CLOCK(C_NONE);
229: CLOCK(C_CLK);
230:
231: /* Program the 24 bit value into REG0 */
232:
233: for (index = 0; index < 24; index++)
234: {
235: /* Clock in the next bit */
236: clock_value >>= 1;
237: if (clock_value & 1)
238: {
239: CLOCK(C_CLK);
240: CLOCK(C_NONE);
241: CLOCK(C_DATA);
242: CLOCK(C_BOTH);
243: }
244: else
245: {
246: CLOCK(C_BOTH);
247: CLOCK(C_DATA);
248: CLOCK(C_NONE);
249: CLOCK(C_CLK);
250: }
251: }
252:
253: CLOCK(C_BOTH);
254: CLOCK(C_DATA);
255: CLOCK(C_BOTH);
256:
257: /* If necessary, reprogram other ICD2061A registers to defaults */
258:
259: /* Select the CLOCK in the frequency synthesizer */
260:
261: CLOCK(C_NONE | select);
262:
263: /* Turn screen back on */
264:
265: VideoPortWritePortUchar(SEQ_ADDRESS_REG, 0x01);
266: iotemp = VideoPortReadPortUchar(SEQ_DATA_REG);
267: VideoPortWritePortUchar(SEQ_DATA_REG, (UCHAR) (iotemp & 0xDF));
268:
269: }
270:
271: /******************************************************************************
272: * Number theoretic function - GCD (Greatest Common Divisor)
273: *****************************************************************************/
274: long gcd(a, b)
275: register long a, b;
276: {
277: register long c = a % b;
278: while (c)
279: a = b, b = c, c = a % b;
280: return b;
281: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.