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