Rev 54 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
54 | pj | 1 | /* |
2 | * IBMRGB52x.c: |
||
3 | * |
||
4 | * RAMDAC definitions for IBM's RGB52x PaletteDAC. |
||
5 | * |
||
6 | * Portion of this file is derived from XFree86's source code. |
||
7 | * [insert XFree86's copyright here]. |
||
8 | */ |
||
9 | |||
10 | #include <stdio.h> |
||
11 | #include "libvga.h" |
||
12 | |||
13 | #include "timing.h" |
||
14 | #include "vgaregs.h" |
||
15 | #include "driver.h" /* for __svgalib_driver_report */ |
||
16 | #include "ramdac.h" |
||
17 | |||
18 | #include "IBMRGB52x.h" |
||
19 | |||
20 | #define IBMRGB52x_STATESIZE 0x101 |
||
21 | |||
22 | static int IBMRGB52x_dacspeed = 170000; /* assuming 170MHz DAC */ |
||
23 | static int IBMRGB52x_fref = 16000; /* assuming 16MHz refclock */ |
||
24 | static int IBMRGB52x_clk = 2; /* use clock 2 */ |
||
25 | |||
26 | #ifdef INCLUDE_IBMRGB52x_DAC_TEST |
||
27 | /* |
||
28 | * s3IBMRGB_Probe() from XFree86. |
||
29 | * |
||
30 | * returns 0x01xx for 525, 0x02xx for 524/528, where xx = revision. |
||
31 | */ |
||
32 | static int IBMRGB52x_probe(void) |
||
33 | { |
||
34 | unsigned char CR43, CR55, dac[3], lut[6]; |
||
35 | unsigned char ilow, ihigh, id, rev, id2, rev2; |
||
36 | int i, j; |
||
37 | int ret = 0; |
||
38 | |||
39 | port_out(0x43, 0x3D4); |
||
40 | CR43 = port_in(0x3D5); |
||
41 | port_out(CR43 & ~0x02, 0x3D5); |
||
42 | |||
43 | port_out(0x55, 0x3D4); |
||
44 | CR55 = port_in(0x3D5); |
||
45 | port_out(CR55 & ~0x03, 0x3D5); |
||
46 | |||
47 | /* save DAC and first LUT entries */ |
||
48 | for (i = 0; i < 3; i++) |
||
49 | dac[i] = port_in(IBMRGB_PIXEL_MASK + i); |
||
50 | for (i = j = 0; i < 2; i++) { |
||
51 | port_out(i, IBMRGB_READ_ADDR); |
||
52 | lut[j++] = port_in(IBMRGB_RAMDAC_DATA); |
||
53 | lut[j++] = port_in(IBMRGB_RAMDAC_DATA); |
||
54 | lut[j++] = port_in(IBMRGB_RAMDAC_DATA); |
||
55 | } |
||
56 | |||
57 | port_out(0x55, 0x3D4); |
||
58 | port_out((CR55 & ~0x03) | 0x01, 0x3D5); /* set RS2 */ |
||
59 | |||
60 | /* read ID and revision */ |
||
61 | ilow = port_in(IBMRGB_INDEX_LOW); |
||
62 | ihigh = port_in(IBMRGB_INDEX_HIGH); |
||
63 | port_out(0, IBMRGB_INDEX_HIGH); /* index high */ |
||
64 | port_out(IBMRGB_rev, IBMRGB_INDEX_LOW); |
||
65 | rev = port_in(IBMRGB_INDEX_DATA); |
||
66 | port_out(IBMRGB_id, IBMRGB_INDEX_LOW); |
||
67 | id = port_in(IBMRGB_INDEX_DATA); |
||
68 | |||
69 | /* known IDs: |
||
70 | 1 = RGB525 |
||
71 | 2 = RGB524, RGB528 |
||
72 | */ |
||
73 | |||
74 | if (id >= 1 && id <= 2) { |
||
75 | /* check if ID and revision are read only */ |
||
76 | port_out(IBMRGB_rev, IBMRGB_INDEX_LOW); |
||
77 | port_out(~rev, IBMRGB_INDEX_DATA); |
||
78 | port_out(IBMRGB_id, IBMRGB_INDEX_LOW); |
||
79 | port_out(~id, IBMRGB_INDEX_DATA); |
||
80 | port_out(IBMRGB_rev, IBMRGB_INDEX_LOW); |
||
81 | rev2 = port_in(IBMRGB_INDEX_DATA); |
||
82 | port_out(IBMRGB_id, IBMRGB_INDEX_LOW); |
||
83 | id2 = port_in(IBMRGB_INDEX_DATA); |
||
84 | |||
85 | if (id == id2 && rev == rev2) { /* IBM RGB52x found */ |
||
86 | ret = (id << 8) | rev; |
||
87 | } else { |
||
88 | port_out(IBMRGB_rev, IBMRGB_INDEX_LOW); |
||
89 | port_out(rev, IBMRGB_INDEX_DATA); |
||
90 | port_out(IBMRGB_id, IBMRGB_INDEX_LOW); |
||
91 | port_out(id, IBMRGB_INDEX_DATA); |
||
92 | } |
||
93 | } |
||
94 | port_out(ilow, IBMRGB_INDEX_LOW); |
||
95 | port_out(ihigh, IBMRGB_INDEX_HIGH); |
||
96 | |||
97 | port_out(0x55, 0x3D4); |
||
98 | port_out(CR55 & ~0x03, 0x3D5); /* reset RS2 */ |
||
99 | |||
100 | /* restore DAC and first LUT entries */ |
||
101 | for (i = j = 0; i < 2; i++) { |
||
102 | port_out(i, IBMRGB_WRITE_ADDR); |
||
103 | port_out(lut[j++], IBMRGB_RAMDAC_DATA); |
||
104 | port_out(lut[j++], IBMRGB_RAMDAC_DATA); |
||
105 | port_out(lut[j++], IBMRGB_RAMDAC_DATA); |
||
106 | } |
||
107 | for (i = 0; i < 3; i++) |
||
108 | port_out(dac[i], IBMRGB_PIXEL_MASK + i); |
||
109 | |||
110 | port_out(0x43, 0x3D4); |
||
111 | port_out(CR43, 0x3D5); |
||
112 | port_out(0x55, 0x3D4); |
||
113 | port_out(CR55, 0x3D5); |
||
114 | |||
115 | return ret; |
||
116 | } |
||
117 | #else |
||
118 | #define IBMRGB52x_probe 0 |
||
119 | #endif |
||
120 | |||
121 | #ifdef INCLUDE_IBMRGB52x_DAC |
||
122 | static void IBMRGBSetClock(long freq, int clk, long dacspeed, long fref, |
||
123 | int *best_m_out, int *best_n_out, int *best_df_out) |
||
124 | { |
||
125 | volatile double ffreq, fdacspeed, ffref; |
||
126 | volatile int df, n, m, max_n, min_df; |
||
127 | volatile int best_m = 69, best_n = 17, best_df = 0; |
||
128 | volatile double diff, mindiff; |
||
129 | |||
130 | #define FREQ_MIN 16250 /* 1000 * (0+65) / 4 */ |
||
131 | #define FREQ_MAX dacspeed |
||
132 | |||
133 | if (freq < FREQ_MIN) |
||
134 | ffreq = FREQ_MIN / 1000.0; |
||
135 | else if (freq > FREQ_MAX) |
||
136 | ffreq = FREQ_MAX / 1000.0; |
||
137 | else |
||
138 | ffreq = freq / 1000.0; |
||
139 | |||
140 | fdacspeed = dacspeed / 1e3; |
||
141 | ffref = fref / 1e3; |
||
142 | |||
143 | ffreq /= ffref; |
||
144 | ffreq *= 16; |
||
145 | mindiff = ffreq; |
||
146 | |||
147 | if (freq <= dacspeed / 4) |
||
148 | min_df = 0; |
||
149 | else if (freq <= dacspeed / 2) |
||
150 | min_df = 1; |
||
151 | else |
||
152 | min_df = 2; |
||
153 | |||
154 | for (df = 0; df < 4; df++) { |
||
155 | ffreq /= 2; |
||
156 | mindiff /= 2; |
||
157 | if (df < min_df) |
||
158 | continue; |
||
159 | |||
160 | /* the remaining formula is ffreq = (m+65) / n */ |
||
161 | |||
162 | if (df < 3) |
||
163 | max_n = fref / 1000 / 2; |
||
164 | else |
||
165 | max_n = fref / 1000; |
||
166 | if (max_n > 31) |
||
167 | max_n = 31; |
||
168 | |||
169 | for (n = 2; n <= max_n; n++) { |
||
170 | m = (int) (ffreq * n + 0.5) - 65; |
||
171 | if (m < 0) |
||
172 | m = 0; |
||
173 | else if (m > 63) |
||
174 | m = 63; |
||
175 | |||
176 | diff = (m + 65.0) / n - ffreq; |
||
177 | if (diff < 0) |
||
178 | diff = -diff; |
||
179 | |||
180 | if (diff < mindiff) { |
||
181 | mindiff = diff; |
||
182 | best_n = n; |
||
183 | best_m = m; |
||
184 | best_df = df; |
||
185 | } |
||
186 | } |
||
187 | } |
||
188 | |||
189 | #ifdef DEBUG |
||
81 | giacomo | 190 | cprintf("clk %d, setting to %f, m 0x%02x %d, n 0x%02x %d, df %d\n", clk, |
54 | pj | 191 | ((best_m + 65.0) / best_n) / (8 >> best_df) * ffref, |
192 | best_m, best_m, best_n, best_n, best_df); |
||
193 | #endif |
||
194 | *best_m_out = best_m; |
||
195 | *best_n_out = best_n; |
||
196 | *best_df_out = best_df; |
||
197 | } |
||
198 | |||
199 | static void IBMRGB52x_init(void) |
||
200 | { |
||
201 | unsigned char tmp, CR55; |
||
202 | #ifdef INCLUDE_IBMRGB52x_DAC_TEST |
||
203 | int idrev; |
||
204 | |||
205 | idrev = IBMRGB52x_probe(); |
||
206 | if (__svgalib_driver_report) |
||
81 | giacomo | 207 | cprintf("svgalib: Using IBM RGB 52%d PaletteDAC, revision %d.\n", |
54 | pj | 208 | (idrev >> 8) == 1 ? 5 : 4, |
209 | idrev & 0xff); |
||
210 | #else |
||
211 | if (__svgalib_driver_report) |
||
81 | giacomo | 212 | cprintf("svgalib: Using IBM RGB 52x PaletteDAC.\n"); |
54 | pj | 213 | #endif |
214 | /* set RS2 */ |
||
215 | port_out(0x55, 0x3D4); |
||
216 | CR55 = port_in(0x3D5) & 0xFC; |
||
217 | port_out(CR55 | 0x01, 0x3D5); |
||
218 | |||
219 | tmp = port_in(IBMRGB_INDEX_CONTROL); |
||
220 | port_out(tmp & ~0x01, IBMRGB_INDEX_CONTROL); /* turn off auto-increment */ |
||
221 | port_out(0, IBMRGB_INDEX_HIGH); /* reset index high */ |
||
222 | |||
223 | __svgalib_outCR(0x55, CR55); |
||
224 | } |
||
225 | |||
226 | static int IBMRGB52x_match_programmable_clock(int desiredclock) |
||
227 | { |
||
228 | int m, n, df; |
||
229 | |||
230 | IBMRGBSetClock(desiredclock, IBMRGB52x_clk, IBMRGB52x_dacspeed, |
||
231 | IBMRGB52x_fref, &m, &n, &df); |
||
232 | |||
233 | return ((m + 65.0) / n) / (8 >> df) * IBMRGB52x_fref; |
||
234 | } |
||
235 | |||
236 | static void IBMRGB52x_initialize_clock_state(unsigned char *regs, int freq) |
||
237 | { |
||
238 | int m, n, df; |
||
239 | |||
240 | IBMRGBSetClock(freq, IBMRGB52x_clk, IBMRGB52x_dacspeed, |
||
241 | IBMRGB52x_fref, &m, &n, &df); |
||
242 | |||
243 | if (__svgalib_driver_report) |
||
81 | giacomo | 244 | cprintf("clk %d, setting to %.3f, m 0x%02x %d, n 0x%02x %d, df %d\n", |
54 | pj | 245 | IBMRGB52x_clk, ((m + 65.0) / n) / (8 >> df) * IBMRGB52x_fref / 1000, |
246 | m, m, n, n, df); |
||
247 | |||
248 | regs[IBMRGB_misc_clock] |= 0x01; |
||
249 | regs[IBMRGB_m0 + 2 * IBMRGB52x_clk] = (df << 6) | (m & 0x3f); |
||
250 | regs[IBMRGB_n0 + 2 * IBMRGB52x_clk] = n; |
||
251 | regs[IBMRGB_pll_ctrl2] &= 0xf0; |
||
252 | regs[IBMRGB_pll_ctrl2] |= IBMRGB52x_clk; |
||
253 | regs[IBMRGB_pll_ctrl1] &= 0xf8; |
||
254 | regs[IBMRGB_pll_ctrl1] |= 0x03; |
||
255 | } |
||
256 | |||
257 | static void IBMRGB52x_savestate(unsigned char *regs) |
||
258 | { |
||
259 | int i; |
||
260 | unsigned char tmp; |
||
261 | |||
262 | /* set RS2 */ |
||
263 | port_out(0x55, 0x3D4); |
||
264 | tmp = port_in(0x3D5) & 0xFC; |
||
265 | port_out(tmp | 0x01, 0x3D5); |
||
266 | |||
267 | for (i = 0; i < 0x100; i++) { |
||
268 | port_out(i, IBMRGB_INDEX_LOW); /* high index is set to 0 */ |
||
269 | regs[i] = port_in(IBMRGB_INDEX_DATA); |
||
270 | } |
||
271 | regs[0x100] = __svgalib_inCR(0x22); |
||
272 | |||
273 | __svgalib_outCR(0x55, tmp); |
||
274 | } |
||
275 | |||
276 | /* SL: not complete, need more work for 525. */ |
||
277 | static void IBMRGB52x_restorestate(const unsigned char *regs) |
||
278 | { |
||
279 | int i; |
||
280 | unsigned char tmp; |
||
281 | |||
282 | /* set RS2 */ |
||
283 | port_out(0x55, 0x3D4); |
||
284 | tmp = port_in(0x3D5) & 0xFC; |
||
285 | port_out(tmp | 0x01, 0x3D5); |
||
286 | |||
287 | for (i = 0; i < 0x100; i++) { |
||
288 | port_out(i, IBMRGB_INDEX_LOW); /* high index is set to 0 */ |
||
289 | port_out(regs[i], IBMRGB_INDEX_DATA); |
||
290 | } |
||
291 | __svgalib_outCR(0x22, regs[0x100]); |
||
292 | |||
293 | __svgalib_outCR(0x55, tmp); |
||
294 | } |
||
295 | |||
296 | static int IBMRGB52x_map_clock(int bpp, int pixelclock) |
||
297 | { |
||
298 | return pixelclock; |
||
299 | } |
||
300 | |||
301 | static int IBMRGB52x_map_horizontal_crtc(int bpp, int pixelclock, int htiming) |
||
302 | { |
||
303 | #ifdef PIXEL_MULTIPLEXING |
||
304 | switch (bpp) { |
||
305 | case 4: |
||
306 | break; |
||
307 | case 8: |
||
308 | return htiming / 2; |
||
309 | case 16: |
||
310 | break; |
||
311 | case 24: |
||
312 | return htiming * 3 / 2; |
||
313 | case 32: |
||
314 | return htiming * 2; |
||
315 | } |
||
316 | #endif |
||
317 | return htiming; |
||
318 | } |
||
319 | |||
320 | static void IBMRGB52x_initializestate(unsigned char *regs, int bpp, int colormode, |
||
321 | int pixelclock) |
||
322 | { |
||
323 | unsigned char tmp; |
||
324 | |||
325 | regs[IBMRGB_misc_clock] = (regs[IBMRGB_misc_clock] & 0xf0) | 0x03; |
||
326 | regs[IBMRGB_sync] = 0; |
||
327 | regs[IBMRGB_hsync_pos] = 0; |
||
328 | regs[IBMRGB_pwr_mgmt] = 0; |
||
329 | regs[IBMRGB_dac_op] &= ~0x08; /* no sync on green */ |
||
330 | regs[IBMRGB_dac_op] |= 0x02; /* fast slew */ |
||
331 | regs[IBMRGB_pal_ctrl] = 0; |
||
332 | regs[IBMRGB_misc1] &= ~0x43; |
||
333 | regs[IBMRGB_misc1] |= 1; |
||
334 | #ifdef PIXEL_MULTIPLEXING |
||
335 | if (bpp >= 8) |
||
336 | regs[IBMRGB_misc2] = 0x43; /* use SID bus? 0x47 for DAC_8_BIT */ |
||
337 | #endif |
||
338 | tmp = __svgalib_inCR(0x22); |
||
339 | if (bpp <= 8) /* and 968 */ |
||
340 | __svgalib_outCR(0x22, tmp | 0x08); |
||
341 | else |
||
342 | __svgalib_outCR(0x22, tmp & ~0x08); |
||
343 | |||
344 | regs[IBMRGB_pix_fmt] &= ~0x07; |
||
345 | switch (bpp) { |
||
346 | case 4: |
||
347 | case 8: |
||
348 | regs[IBMRGB_pix_fmt] |= 0x03; |
||
349 | regs[IBMRGB_8bpp] = 0x00; |
||
350 | break; |
||
351 | case 15: |
||
352 | regs[IBMRGB_pix_fmt] |= 0x04; |
||
353 | regs[IBMRGB_16bpp] = 0x02; |
||
354 | break; |
||
355 | case 16: |
||
356 | regs[IBMRGB_pix_fmt] |= 0x04; |
||
357 | regs[IBMRGB_16bpp] = 0x00; |
||
358 | break; |
||
359 | case 24: |
||
360 | regs[IBMRGB_pix_fmt] |= 0x05; /* SL: guess */ |
||
361 | regs[IBMRGB_24bpp] = 0x00; |
||
362 | break; |
||
363 | case 32: |
||
364 | regs[IBMRGB_pix_fmt] |= 0x06; |
||
365 | regs[IBMRGB_32bpp] = 0x00; |
||
366 | break; |
||
367 | } |
||
368 | IBMRGB52x_initialize_clock_state(regs, |
||
369 | IBMRGB52x_map_clock(bpp, pixelclock)); |
||
370 | } |
||
371 | |||
372 | static void IBMRGB52x_qualify_cardspecs(CardSpecs * cardspecs, int dacspeed) |
||
373 | { |
||
374 | IBMRGB52x_dacspeed = __svgalib_setDacSpeed(dacspeed, 170000); /* 220 MHz version exist also */ |
||
375 | cardspecs->maxPixelClock4bpp = IBMRGB52x_dacspeed; |
||
376 | cardspecs->maxPixelClock8bpp = IBMRGB52x_dacspeed; |
||
377 | #ifdef PIXEL_MULTIPLEXING |
||
378 | cardspecs->maxPixelClock16bpp = IBMRGB52x_dacspeed; |
||
379 | cardspecs->maxPixelClock24bpp = IBMRGB52x_dacspeed * 3 / 2; |
||
380 | cardspecs->maxPixelClock32bpp = IBMRGB52x_dacspeed / 2; |
||
381 | #else |
||
382 | cardspecs->maxPixelClock16bpp = 0; |
||
383 | cardspecs->maxPixelClock24bpp = 0; |
||
384 | cardspecs->maxPixelClock32bpp = 0; |
||
385 | #endif |
||
386 | cardspecs->mapClock = IBMRGB52x_map_clock; |
||
387 | cardspecs->matchProgrammableClock = IBMRGB52x_match_programmable_clock; |
||
388 | cardspecs->mapHorizontalCrtc = IBMRGB52x_map_horizontal_crtc; |
||
389 | cardspecs->flags |= CLOCK_PROGRAMMABLE; |
||
390 | } |
||
391 | |||
392 | DacMethods __svgalib_IBMRGB52x_methods = |
||
393 | { |
||
394 | IBMRGB52x, |
||
395 | "IBM RGB 52x PaletteDAC", |
||
396 | DAC_HAS_PROGRAMMABLE_CLOCKS, |
||
397 | IBMRGB52x_probe, |
||
398 | IBMRGB52x_init, |
||
399 | IBMRGB52x_qualify_cardspecs, |
||
400 | IBMRGB52x_savestate, |
||
401 | IBMRGB52x_restorestate, |
||
402 | IBMRGB52x_initializestate, |
||
403 | IBMRGB52x_STATESIZE |
||
404 | }; |
||
405 | #endif |