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 */
IBMRGB52x_probe(void)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
IBMRGBSetClock(long freq,int clk,long dacspeed,long fref,int * best_m_out,int * best_n_out,int * best_df_out)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
190 printf("clk %d, setting to %f, m 0x%02x %d, n 0x%02x %d, df %d\n", clk,
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
IBMRGB52x_init(void)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)
207 printf("svgalib: Using IBM RGB 52%d PaletteDAC, revision %d.\n",
208 (idrev >> 8) == 1 ? 5 : 4,
209 idrev & 0xff);
210 #else
211 if (__svgalib_driver_report)
212 printf("svgalib: Using IBM RGB 52x PaletteDAC.\n");
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
IBMRGB52x_match_programmable_clock(int desiredclock)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
IBMRGB52x_initialize_clock_state(unsigned char * regs,int freq)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)
244 printf("clk %d, setting to %.3f, m 0x%02x %d, n 0x%02x %d, df %d\n",
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
IBMRGB52x_savestate(unsigned char * regs)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. */
IBMRGB52x_restorestate(const unsigned char * regs)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
IBMRGB52x_map_clock(int bpp,int pixelclock)296 static int IBMRGB52x_map_clock(int bpp, int pixelclock)
297 {
298 return pixelclock;
299 }
300
IBMRGB52x_map_horizontal_crtc(int bpp,int pixelclock,int htiming)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
IBMRGB52x_initializestate(unsigned char * regs,int bpp,int colormode,int pixelclock)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
IBMRGB52x_qualify_cardspecs(CardSpecs * cardspecs,int dacspeed)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
406