📄 s3dacs.c
字号:
/* * s3dacs.c: * * RAMDAC definitions for the S3-SDAC (86C716), S3-GENDAC, and Trio64. * * These contain S3-specific code. */#include <stdio.h>#include "libvga.h"#include "timing.h"#include "vgaregs.h"#include "driver.h" /* for __svgalib_driver_report */#include "ramdac.h"/* SDAC/GENDAC registers */#if defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC)#define SDAC_COMMAND 0 /* Register offsets into state. */#define GENDAC_COMMAND 0#define SDAC_PLL_WRITEINDEX 1#define SDAC_PLL_READINDEX 2#define SDAC_PLL_M 3 /* f2 programmed clock */#define SDAC_PLL_N1_N2 4#define SDAC_PLL_CONTROL 5#define SDAC_STATESIZE 6 /* 6 registers. */#define GENDAC_STATESIZE 6#endif#if defined(INCLUDE_S3_SDAC_DAC_TEST) || defined(INCLUDE_S3_GENDAC_DAC_TEST)static int GENDAC_SDAC_probe(void){/* Taken from XFree86, accel/s3.c. *//* Return 1 if GENDAC found, 2 if SDAC, 0 otherwise. */ /* probe for S3 GENDAC or SDAC */ /* * S3 GENDAC and SDAC have two fixed read only PLL clocks * CLK0 f0: 25.255MHz M-byte 0x28 N-byte 0x61 * CLK0 f1: 28.311MHz M-byte 0x3d N-byte 0x62 * which can be used to detect GENDAC and SDAC since there is no chip-id * for the GENDAC. * * NOTE: for the GENDAC on a MIRO 10SD (805+GENDAC) reading PLL values * for CLK0 f0 and f1 always returns 0x7f (but is documented "read only") */ unsigned char saveCR55, savelut[6]; int i; long clock01, clock23; saveCR55 = __svgalib_inCR(0x55); __svgalib_outbCR(0x55, saveCR55 & ~1); outb(0x3c7, 0); for (i = 0; i < 2 * 3; i++) /* save first two LUT entries */ savelut[i] = inb(0x3c9); outb(0x3c8, 0); for (i = 0; i < 2 * 3; i++) /* set first two LUT entries to zero */ outb(0x3c9, 0); __svgalib_outbCR(0x55, saveCR55 | 1); outb(0x3c7, 0); for (i = clock01 = 0; i < 4; i++) clock01 = (clock01 << 8) | (inb(0x3c9) & 0xff); for (i = clock23 = 0; i < 4; i++) clock23 = (clock23 << 8) | (inb(0x3c9) & 0xff); __svgalib_outbCR(0x55, saveCR55 & ~1); outb(0x3c8, 0); for (i = 0; i < 2 * 3; i++) /* restore first two LUT entries */ outb(0x3c9, savelut[i]); __svgalib_outbCR(0x55, saveCR55); if (clock01 == 0x28613d62 || (clock01 == 0x7f7f7f7f && clock23 != 0x7f7f7f7f)) { inb(0x3c8); /* dactopel */ inb(0x3c6); inb(0x3c6); inb(0x3c6); /* the forth read will show the SDAC chip ID and revision */ if (((i = inb(0x3c6)) & 0xf0) == 0x70) { return 2; /* SDAC found. */ } else { return 1; /* GENDAC found. */ } inb(0x3c8); /* dactopel */ } return 0;}#endif#if defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC)static void GENDAC_SDAC_init(void){ unsigned char val; int m, n, n1, n2, MCLK; val = __svgalib_inCR(0x55); __svgalib_outbCR(0x55, val | 0x01); outb(0x3C7, 10); /* Read MCLK. */ m = inb(0x3C9); n = inb(0x3C9); __svgalib_outbCR(0x55, val); /* Restore CR55. */ m &= 0x7f; n1 = n & 0x1f; n2 = (n >> 5) & 0x03; /* Calculate MCLK in kHz. */ MCLK = 14318 * (m + 2) / (n1 + 2) / (1 << n2); if (__svgalib_driver_report) printf("svgalib: S3-GENDAC/SDAC: MCLK = %d.%03d MHz\n", MCLK / 1000, MCLK % 1000);}#endif#if defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC) || defined(INCLUDE_S3_TRIO64_DAC)/* * From XFree86 common_hw/S3gendac.c and S3gendac.h. * * Progaming of the S3 gendac programable clocks, from the S3 Gendac * programing documentation by S3 Inc. * Jon Tombs <jon@esix2.us.es> * * Returns nonzero if success, 0 if failure. */#define BASE_FREQ 14.31818 /* MHz */#define DEBUG_FINDCLOCK 0static int S3dacsFindClock(int freq_in, int min_n2, int freq_min, int freq_max, int *best_m_out, int *best_n1_out, int *best_n2_out){ double ffreq_in, ffreq_min, ffreq_max; double ffreq_out, diff, best_diff; unsigned int m; unsigned char n1, n2; unsigned char best_n1 = 16 + 2, best_n2 = 2, best_m = 125 + 2;#if DEBUG_FINDCLOCK printf("S3dacsFindClock: Trying to match clock of %0.3f MHz\n", freq_in / 1000.0);#endif ffreq_in = freq_in / 1000.0 / BASE_FREQ; ffreq_min = freq_min / 1000.0 / BASE_FREQ; ffreq_max = freq_max / 1000.0 / BASE_FREQ; /* Check if getting freq_in is possible at all */ if (freq_in < freq_min / 8) {#if DEBUG_FINDCLOCK printf("S3dacsFindClock: %0.3f MHz is too low (lowest is %0.3f MHz)\n", freq_in / 1000.0, freq_min / 1000.0 / 8);#endif return 0; } if (freq_in > freq_max / (1 << min_n2)) {#if DEBUG_FINDCLOCK printf("S3dacsFindClock: %0.3f MHz is too high (highest is %0.3f MHz)\n", freq_in / 1000.0, freq_max / 1000.0 / (1 << min_n2));#endif return 0; } /* work out suitable timings */ best_diff = ffreq_in; for (n2 = min_n2; n2 <= 3; n2++) { for (n1 = 1 + 2; n1 <= 31 + 2; n1++) { m = (int) (ffreq_in * n1 * (1 << n2) + 0.5); if (m < 1 + 2 || m > 127 + 2) continue; ffreq_out = (double) (m) / (double) (n1); if ((ffreq_out >= ffreq_min) && (ffreq_out <= ffreq_max)) { diff = ffreq_in - ffreq_out / (1 << n2); if (diff < 0.0) diff = -diff; if (diff < best_diff) { best_diff = diff; best_m = m; best_n1 = n1; best_n2 = n2; } } } }#if DEBUG_FINDCLOCK printf("S3dacsFindClock: clock wanted %1.6f MHz, found %1.6f MHz (m %d, n1 %d, n2 %d)\n", freq_in / 1000.0, best_m / ((double) best_n1 * (1 << best_n2)) * BASE_FREQ, best_m, best_n1, best_n2);#endif *best_m_out = best_m; *best_n1_out = best_n1; *best_n2_out = best_n2; return 1;}#endif#if defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC)static int GENDAC_SDAC_match_programmable_clock(int desiredclock){ int min_m, min_n1, n2; /* Note: For ICS5342, min_n2 parameter should be one. */ if (!S3dacsFindClock(desiredclock, 0, 100000, 250000, &min_m, &min_n1, &n2)) return 0; return ((float) (min_m) / (float) (min_n1) / (1 << n2)) * BASE_FREQ * 1000;}#if 0 /* Retained for reference. */static void setdacpll(reg, data1, data2)int reg;unsigned char data1;unsigned char data2;{ unsigned char tmp, tmp1; int vgaCRIndex = vgaIOBase + 4; int vgaCRReg = vgaIOBase + 5; /* set RS2 via CR55, yuck */ tmp = __svgalib_inCR(0x55) & 0xFC; __svgalib_outCR(tmp | 0x01); tmp1 = inb(GENDAC_INDEX); outb(GENDAC_INDEX, reg); outb(GENDAC_DATA, data1); outb(GENDAC_DATA, data2); /* Now clean up our mess */ outb(GENDAC_INDEX, tmp1); __svgalib_outbCR(0x55, tmp);}#endifstatic void GENDAC_SDAC_initialize_clock_state(unsigned char *regs, int freq){ int min_m, min_n1, n2; int n, m; if (!S3dacsFindClock(freq, 0, 100000, 250000, &min_m, &min_n1, &n2)) { printf("Bad dot clock %0.3f MHz.\n", freq / 1000.0); return; } n = (min_n1 - 2) | (n2 << 5); m = min_m - 2; regs[SDAC_PLL_M] = m; regs[SDAC_PLL_N1_N2] = n; if (__svgalib_driver_report) printf("Initializing DAC PLL values; 0x%02X, 0x%02X.\n", m, n);}static void GENDAC_SDAC_savestate(unsigned char *regs){ unsigned char tmp; tmp = __svgalib_inCR(0x55); __svgalib_outbCR(0x55, tmp | 1); regs[SDAC_COMMAND] = inb(0x3c6); regs[SDAC_PLL_WRITEINDEX] = inb(0x3c8); /* PLL write index */ regs[SDAC_PLL_READINDEX] = inb(0x3c7); /* PLL read index */ outb(0x3c7, 2); /* index to f2 reg */ regs[SDAC_PLL_M] = inb(0x3c9); /* f2 PLL M divider */ regs[SDAC_PLL_N1_N2] = inb(0x3c9); /* f2 PLL N1/N2 divider */ outb(0x3c7, 0x0e); /* index to PLL control */ regs[SDAC_PLL_CONTROL] = inb(0x3c9); /* PLL control */ __svgalib_outbCR(0x55, tmp & ~1);}static void GENDAC_SDAC_restorestate(const unsigned char *regs){ unsigned char tmp; /* set RS2 via CR55, yuck */ tmp = __svgalib_inCR(0x55) & 0xFC; __svgalib_outbCR(0x55, tmp | 0x01);#ifdef DEBUG do { int m, n1, n2, clk; m = regs[SDAC_PLL_M] & 0x7f; n1 = regs[SDAC_PLL_N1_N2] & 0x1f; n2 = (regs[SDAC_PLL_N1_N2] & 0x60) >> 5; clk = 14318 * (m + 2) / (n1 + 2) / (1 << n2); printf("SDAC.restorestate, setting clock 0x%02X 0x%02X (%d.%3dMHz)\n", regs[SDAC_PLL_M], regs[SDAC_PLL_N1_N2], clk / 1000, clk % 1000); } while (0);#endif outb(0x3c6, regs[SDAC_COMMAND]); outb(0x3c8, 2); /* index to f2 reg */ outb(0x3c9, regs[SDAC_PLL_M]); /* f2 PLL M divider */ outb(0x3c9, regs[SDAC_PLL_N1_N2]); /* f2 PLL N1/N2 divider */ outb(0x3c8, 0x0e); /* index to PLL control */ outb(0x3c9, regs[SDAC_PLL_CONTROL]); /* PLL control */ outb(0x3c8, regs[SDAC_PLL_WRITEINDEX]); /* PLL write index */ outb(0x3c7, regs[SDAC_PLL_READINDEX]); /* PLL read index */ __svgalib_outbCR(0x55, tmp);}#endif /* defined(INCLUDE_S3_SDAC_DAC) || defined(INCLUDE_S3_GENDAC_DAC) *//* * SDAC: 16-bit DAC, 110 MHz raw clock limit. * * The 135 MHz version supports pixel multiplexing in 8bpp modes with a * halved raw clock. (SL: at least mine doesn't.) */#ifdef INCLUDE_S3_SDAC_DAC_TESTstatic int SDAC_probe(void){ return GENDAC_SDAC_probe() == 2;}#else#define SDAC_probe 0#endif#ifdef INCLUDE_S3_SDAC_DACstatic int SDAC_map_clock(int bpp, int pixelclock){ switch (bpp) { case 4: case 8:#ifdef SDAC_8BPP_PIXMUX /* SL: AFAIK it doesn't work */ if (pixelclock >= 67500) /* Use pixel multiplexing. */ return pixelclock / 2;#endif break; case 24: return pixelclock * 3 / 2; case 32: return pixelclock * 2; } return pixelclock;}static int SDAC_map_horizontal_crtc(int bpp, int pixelclock, int htiming){ switch (bpp) { case 16: return htiming * 2; case 24: return htiming * 3; case 32: return htiming * 4; } return htiming;}static void SDAC_initializestate(unsigned char *regs, int bpp, int colormode, int pixelclock){ int pixmux; /* SDAC command register. */ pixmux = 0; switch (colormode) { case CLUT8_6:#ifdef SDAC_8BPP_PIXMUX if (pixelclock >= 67500) pixmux = 0x10;#endif break; case RGB16_555:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -