📄 matroxfb_dac1064.c
字号:
/* * * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. * * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> * * Version: 1.54 2001/09/09 * * See matroxfb_base.c for contributors. * *//* make checkconfig does not walk through include tree :-( */#include <linux/config.h>#include "matroxfb_DAC1064.h"#include "matroxfb_misc.h"#include "matroxfb_accel.h"#include <linux/matroxfb.h>#ifdef NEED_DAC1064#define outDAC1064 matroxfb_DAC_out#define inDAC1064 matroxfb_DAC_in#define DAC1064_OPT_SCLK_PCI 0x00#define DAC1064_OPT_SCLK_PLL 0x01#define DAC1064_OPT_SCLK_EXT 0x02#define DAC1064_OPT_SCLK_MASK 0x03#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */#define DAC1064_OPT_GDIV3 0x00#define DAC1064_OPT_MDIV1 0x08#define DAC1064_OPT_MDIV2 0x00#define DAC1064_OPT_RESERVED 0x10static void matroxfb_DAC1064_flashcursor(unsigned long ptr) { unsigned long flags;#define minfo ((struct matrox_fb_info*)ptr) matroxfb_DAC_lock_irqsave(flags); outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA); ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; add_timer(&ACCESS_FBINFO(cursor.timer)); matroxfb_DAC_unlock_irqrestore(flags);#undef minfo}static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) { vaddr_t cursorbase; u_int32_t xline; unsigned int i; unsigned int h, to; CRITFLAGS if (ACCESS_FBINFO(currcon_display) != p) return; matroxfb_createcursorshape(PMINFO p, p->var.vmode); xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); cursorbase = ACCESS_FBINFO(video.vbase); h = ACCESS_FBINFO(features.DAC1064.cursorimage); CRITBEGIN#ifdef __BIG_ENDIAN WaitTillIdle(); mga_outl(M_OPMODE, M_OPMODE_32BPP);#endif to = ACCESS_FBINFO(cursor.u); for (i = 0; i < to; i++) { mga_writel(cursorbase, h, 0); mga_writel(cursorbase, h+4, 0); mga_writel(cursorbase, h+8, ~0); mga_writel(cursorbase, h+12, ~0); h += 16; } to = ACCESS_FBINFO(cursor.d); for (; i < to; i++) { mga_writel(cursorbase, h, 0); mga_writel(cursorbase, h+4, xline); mga_writel(cursorbase, h+8, ~0); mga_writel(cursorbase, h+12, ~0); h += 16; } for (; i < 64; i++) { mga_writel(cursorbase, h, 0); mga_writel(cursorbase, h+4, 0); mga_writel(cursorbase, h+8, ~0); mga_writel(cursorbase, h+12, ~0); h += 16; }#ifdef __BIG_ENDIAN mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));#endif CRITEND}static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) { unsigned long flags; MINFO_FROM_DISP(p); if (ACCESS_FBINFO(currcon_display) != p) return; if (mode == CM_ERASE) { if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { del_timer_sync(&ACCESS_FBINFO(cursor.timer)); matroxfb_DAC_lock_irqsave(flags); ACCESS_FBINFO(cursor.state) = CM_ERASE; outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); matroxfb_DAC_unlock_irqrestore(flags); } return; } if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) matroxfb_DAC1064_createcursor(PMINFO p); x *= fontwidth(p); y *= fontheight(p); y -= p->var.yoffset; if (p->var.vmode & FB_VMODE_DOUBLE) y *= 2; del_timer_sync(&ACCESS_FBINFO(cursor.timer)); matroxfb_DAC_lock_irqsave(flags); if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) { ACCESS_FBINFO(cursor.redraw) = 0; ACCESS_FBINFO(cursor.x) = x; ACCESS_FBINFO(cursor.y) = y; x += 64; y += 64; outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); mga_outb(M_RAMDAC_BASE+M1064_CURPOSXL, x); mga_outb(M_RAMDAC_BASE+M1064_CURPOSXH, x >> 8); mga_outb(M_RAMDAC_BASE+M1064_CURPOSYL, y); mga_outb(M_RAMDAC_BASE+M1064_CURPOSYH, y >> 8); } ACCESS_FBINFO(cursor.state) = CM_DRAW; if (ACCESS_FBINFO(devflags.blink)) mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_XGA); matroxfb_DAC_unlock_irqrestore(flags);}static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) { if (p && p->conp) matroxfb_DAC1064_createcursor(PMXINFO(p) p); return 0;}static int DAC1064_selhwcursor(WPMINFO struct display* p) { ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor; ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont; return 0;}static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) { unsigned int fvco; unsigned int p; DBG("DAC1064_calcclock") fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p); if (ACCESS_FBINFO(devflags.g450dac)) { if (fvco <= 300000) /* 276-324 */ ; else if (fvco <= 400000) /* 378-438 */ p |= 0x08; else if (fvco <= 550000) /* 540-567 */ p |= 0x10; else if (fvco <= 690000) /* 675-695 */ p |= 0x18; else if (fvco <= 800000) /* 776-803 */ p |= 0x20; else if (fvco <= 891000) /* 891-891 */ p |= 0x28; else if (fvco <= 940000) /* 931-945 */ p |= 0x30; else /* <959 */ p |= 0x38; } else { p = (1 << p) - 1; if (fvco <= 100000) ; else if (fvco <= 140000) p |= 0x08; else if (fvco <= 180000) p |= 0x10; else p |= 0x18; } *post = p;}/* they must be in POS order */static const unsigned char MGA1064_DAC_regs[] = { M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL, M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE, M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE, M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE, DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL, M1064_XMISCCTRL, M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST, M1064_XCRCBITSEL, M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };static const unsigned char MGA1064_DAC[] = { 0x00, 0x00, M1064_XCURCTRL_DIS, 0x00, 0x00, 0x00, /* black */ 0xFF, 0xFF, 0xFF, /* white */ 0xFF, 0x00, 0x00, /* red */ 0x00, 0, M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL, M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN, M1064_XMISCCTRL_DAC_8BIT, 0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN, 0x00, 0x00, 0x00, 0xFF, 0xFF};static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) { unsigned int m, n, p; DBG("DAC1064_setpclk") DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); hw->DACclk[0] = m; hw->DACclk[1] = n; hw->DACclk[2] = p;}static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){ u_int32_t mx; DBG("DAC1064_setmclk") if (ACCESS_FBINFO(devflags.noinit)) { /* read MCLK and give up... */ hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM); hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN); hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP); return; } mx = hw->MXoptionReg | 0x00000004; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); mx &= ~0x000000BB; if (oscinfo & DAC1064_OPT_GDIV1) mx |= 0x00000008; if (oscinfo & DAC1064_OPT_MDIV1) mx |= 0x00000010; if (oscinfo & DAC1064_OPT_RESERVED) mx |= 0x00000080; if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) { /* select PCI clock until we have setup oscilator... */ int clk; unsigned int m, n, p; /* powerup system PLL, select PCI clock */ mx |= 0x00000020; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); mx &= ~0x00000004; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); /* !!! you must not access device if MCLK is not running !!! Doing so cause immediate PCI lockup :-( Maybe they should generate ABORT or I/O (parity...) error and Linux should recover from this... (kill driver/process). But world is not perfect... */ /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not select PLL... because of PLL can be stopped at this time) */ DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m); outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n); outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p); for (clk = 65536; clk; --clk) { if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40) break; } if (!clk) printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n"); /* select PLL */ mx |= 0x00000005; } else { /* select specified system clock source */ mx |= oscinfo & DAC1064_OPT_SCLK_MASK; } pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); mx &= ~0x00000004; pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx); hw->MXoptionReg = mx;}void DAC1064_global_init(CPMINFO struct matrox_hw_state* hw) { hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK; hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN; hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL; hw->DACreg[POS1064_XOUTPUTCONN] = 0x01; /* output #1 enabled */ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) { if (ACCESS_FBINFO(devflags.g450dac)) { hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL2; hw->DACreg[POS1064_XOUTPUTCONN] = 0x05; /* output #1 enabled; CRTC1 connected to output #2 */ } else { hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT; hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12; } } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) { hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12; hw->DACreg[POS1064_XOUTPUTCONN] = 0x09; /* output #1 enabled; CRTC2 connected to output #2 */ } else if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12; else hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS; if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY) hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;}void DAC1064_global_restore(CPMINFO const struct matrox_hw_state* hw) { outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]); outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]); if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) { outDAC1064(PMINFO 0x20, 0x04); outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type)); if (ACCESS_FBINFO(devflags.g450dac)) { outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC); /* only matrox know... */ outDAC1064(PMINFO M1064_XPWRCTRL, 0x1F); /* powerup everything */ outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]); } }}static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display *p) { DBG("DAC1064_init_1") memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); if (p->type == FB_TYPE_TEXT) { hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_6BIT; hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; } else { switch (p->var.bits_per_pixel) { /* case 4: not supported by MGA1064 DAC */ case 8: hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; break; case 16: if (p->var.green.length == 5) hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; else hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; break; case 24: hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; break; case 32: hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; break; default: return 1; /* unsupported depth */ } } DAC1064_global_init(PMINFO hw); hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl); hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK; hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN; hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10; hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18; return 0;}static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) { DBG("DAC1064_init_2") if (p->var.bits_per_pixel > 16) { /* 256 entries */ int i; for (i = 0; i < 256; i++) { hw->DACpal[i * 3 + 0] = i; hw->DACpal[i * 3 + 1] = i; hw->DACpal[i * 3 + 2] = i; } } else if (p->var.bits_per_pixel > 8) { if (p->var.green.length == 5) { /* 0..31, 128..159 */ int i; for (i = 0; i < 32; i++) { /* with p15 == 0 */ hw->DACpal[i * 3 + 0] = i << 3; hw->DACpal[i * 3 + 1] = i << 3; hw->DACpal[i * 3 + 2] = i << 3; /* with p15 == 1 */ hw->DACpal[(i + 128) * 3 + 0] = i << 3; hw->DACpal[(i + 128) * 3 + 1] = i << 3; hw->DACpal[(i + 128) * 3 + 2] = i << 3; } } else { int i; for (i = 0; i < 64; i++) { /* 0..63 */ hw->DACpal[i * 3 + 0] = i << 3; hw->DACpal[i * 3 + 1] = i << 2; hw->DACpal[i * 3 + 2] = i << 3; } } } else { memset(hw->DACpal, 0, 768); } return 0;}static void DAC1064_restore_1(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) { CRITFLAGS DBG("DAC1064_restore_1") CRITBEGIN outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]); outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]); outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]); /* * We must ALWAYS reprogram hardware due to broken XF4 matrox drivers... * * if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) */ { unsigned int i; for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL)) outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]); } } DAC1064_global_restore(PMINFO hw); CRITEND};static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {#ifdef DEBUG unsigned int i;#endif DBG("DAC1064_restore_2") matrox_init_putc(PMINFO p, matroxfb_DAC1064_createcursor);#ifdef DEBUG dprintk(KERN_DEBUG "DAC1064regs "); for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]); if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... "); } dprintk("\n" KERN_DEBUG "DAC1064clk "); for (i = 0; i < 6; i++) dprintk("C%02X=%02X ", i, hw->DACclk[i]); dprintk("\n");#endif}static int m1064_compute(void* outdev, struct my_timming* m, struct matrox_hw_state* hw) {#define minfo ((struct matrox_fb_info*)outdev) DAC1064_setpclk(PMINFO hw, m->pixclock);#undef minfo return 0;}static int m1064_program(void* outdev, const struct matrox_hw_state* hw) {#define minfo ((struct matrox_fb_info*)outdev)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -