📄 matroxfb_crtc2.c
字号:
/* * * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. * * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> * * Portions Copyright (c) 2001 Matrox Graphics Inc. * * Version: 1.65 2002/08/14 * */#include "matroxfb_maven.h"#include "matroxfb_crtc2.h"#include "matroxfb_misc.h"#include "matroxfb_DAC1064.h"#include <linux/matroxfb.h>#include <asm/uaccess.h>/* **************************************************** */static int mem = 8192;module_param(mem, int, 0);MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)");/* **************************************************** */static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info* info) { u_int32_t col;#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) if (regno >= 16) return 1; if (m2info->fbcon.var.grayscale) { /* gray = 0.30*R + 0.59*G + 0.11*B */ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; } red = CNVT_TOHW(red, m2info->fbcon.var.red.length); green = CNVT_TOHW(green, m2info->fbcon.var.green.length); blue = CNVT_TOHW(blue, m2info->fbcon.var.blue.length); transp = CNVT_TOHW(transp, m2info->fbcon.var.transp.length); col = (red << m2info->fbcon.var.red.offset) | (green << m2info->fbcon.var.green.offset) | (blue << m2info->fbcon.var.blue.offset) | (transp << m2info->fbcon.var.transp.offset); switch (m2info->fbcon.var.bits_per_pixel) { case 16: m2info->cmap[regno] = col | (col << 16); break; case 32: m2info->cmap[regno] = col; break; } return 0;#undef m2info}static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, struct my_timming* mt, int mode, unsigned int pos) { u_int32_t tmp; u_int32_t datactl; MINFO_FROM(m2info->primary_dev); switch (mode) { case 15: tmp = 0x00200000; break; case 16: tmp = 0x00400000; break;/* case 32: */ default: tmp = 0x00800000; break; } tmp |= 0x00000001; /* enable CRTC2 */ datactl = 0; if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) { if (ACCESS_FBINFO(devflags.g450dac)) { tmp |= 0x00000006; /* source from secondary pixel PLL */ /* no vidrst when in monitor mode */ if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) { tmp |= 0xC0001000; /* Enable H/V vidrst */ } } else { tmp |= 0x00000002; /* source from VDOCLK */ tmp |= 0xC0000000; /* enable vvidrst & hvidrst */ /* MGA TVO is our clock source */ } } else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) { tmp |= 0x00000004; /* source from pixclock */ /* PIXPLL is our clock source */ } if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) { tmp |= 0x00100000; /* connect CRTC2 to DAC */ } if (mt->interlaced) { tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */ mt->VDisplay >>= 1; mt->VSyncStart >>= 1; mt->VSyncEnd >>= 1; mt->VTotal >>= 1; } if ((mt->HTotal & 7) == 2) { datactl |= 0x00000010; mt->HTotal &= ~7; } tmp |= 0x10000000; /* 0x10000000 is VIDRST polarity */ mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8)); mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8)); mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1)); mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1)); mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */ { u_int32_t linelen = m2info->fbcon.var.xres_virtual * (m2info->fbcon.var.bits_per_pixel >> 3); if (tmp & 0x02000000) { /* field #0 is smaller, so... */ mga_outl(0x3C2C, pos); /* field #1 vmemory start */ mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */ linelen <<= 1; m2info->interlaced = 1; } else { mga_outl(0x3C28, pos); /* vmemory start */ m2info->interlaced = 0; } mga_outl(0x3C40, linelen); } mga_outl(0x3C4C, datactl); /* data control */ if (tmp & 0x02000000) { int i; mga_outl(0x3C10, tmp & ~0x02000000); for (i = 0; i < 2; i++) { unsigned int nl; unsigned int lastl = 0; while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) { lastl = nl; } } } mga_outl(0x3C10, tmp); ACCESS_FBINFO(hw).crtc2.ctl = tmp; tmp = mt->VDisplay << 16; /* line compare */ if (mt->sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x00000100; if (mt->sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x00000200; mga_outl(0x3C44, tmp);}static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) { MINFO_FROM(m2info->primary_dev); mga_outl(0x3C10, 0x00000004); /* disable CRTC2, CRTC1->DAC1, PLL as clock source */ ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;}static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) { /* no acceleration for secondary head... */ m2info->cmap[16] = 0xFFFFFFFF;}static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, struct fb_var_screeninfo* var) { unsigned int pos; unsigned int linelen; unsigned int pixelsize; MINFO_FROM(m2info->primary_dev); m2info->fbcon.var.xoffset = var->xoffset; m2info->fbcon.var.yoffset = var->yoffset; pixelsize = m2info->fbcon.var.bits_per_pixel >> 3; linelen = m2info->fbcon.var.xres_virtual * pixelsize; pos = m2info->fbcon.var.yoffset * linelen + m2info->fbcon.var.xoffset * pixelsize; pos += m2info->video.offbase; if (m2info->interlaced) { mga_outl(0x3C2C, pos); mga_outl(0x3C28, pos + linelen); } else { mga_outl(0x3C28, pos); }}static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info, struct fb_var_screeninfo* var, int *visual, int *video_cmap_len, int *mode) { unsigned int mask; unsigned int memlen; unsigned int vramlen; switch (var->bits_per_pixel) { case 16: mask = 0x1F; break; case 32: mask = 0x0F; break; default: return -EINVAL; } vramlen = m2info->video.len_usable; if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; var->xres_virtual = (var->xres_virtual + mask) & ~mask; if (var->yres_virtual > 32767) return -EINVAL; memlen = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel >> 3); if (memlen > vramlen) return -EINVAL; if (var->xoffset + var->xres > var->xres_virtual) var->xoffset = var->xres_virtual - var->xres; if (var->yoffset + var->yres > var->yres_virtual) var->yoffset = var->yres_virtual - var->yres; var->xres &= ~7; var->left_margin &= ~7; var->right_margin &= ~7; var->hsync_len &= ~7; *mode = var->bits_per_pixel; if (var->bits_per_pixel == 16) { if (var->green.length == 5) { var->red.offset = 10; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 15; var->transp.length = 1; *mode = 15; } else { var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; } } else { var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; } *visual = FB_VISUAL_TRUECOLOR; *video_cmap_len = 16; return 0;}static int matroxfb_dh_open(struct fb_info* info, int user) {#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) MINFO_FROM(m2info->primary_dev); if (MINFO) { int err; if (ACCESS_FBINFO(dead)) { return -ENXIO; } err = ACCESS_FBINFO(fbops).fb_open(&ACCESS_FBINFO(fbcon), user); if (err) { return err; } } return 0;#undef m2info}static int matroxfb_dh_release(struct fb_info* info, int user) {#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) int err = 0; MINFO_FROM(m2info->primary_dev); if (MINFO) { err = ACCESS_FBINFO(fbops).fb_release(&ACCESS_FBINFO(fbcon), user); } return err;#undef m2info}static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) { struct fb_fix_screeninfo *fix = &m2info->fbcon.fix; strcpy(fix->id, "MATROX DH"); fix->smem_start = m2info->video.base; fix->smem_len = m2info->video.len_usable; fix->ypanstep = 1; fix->ywrapstep = 0; fix->xpanstep = 8; /* TBD */ fix->mmio_start = m2info->mmio.base; fix->mmio_len = m2info->mmio.len; fix->accel = 0; /* no accel... */}static int matroxfb_dh_check_var(struct fb_var_screeninfo* var, struct fb_info* info) {#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) int visual; int cmap_len; int mode; return matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode);#undef m2info}static int matroxfb_dh_set_par(struct fb_info* info) {#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) int visual; int cmap_len; int mode; int err; struct fb_var_screeninfo* var = &info->var; MINFO_FROM(m2info->primary_dev); if ((err = matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode)) != 0) return err; /* cmap */ { m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase); m2info->fbcon.fix.visual = visual; m2info->fbcon.fix.type = FB_TYPE_PACKED_PIXELS; m2info->fbcon.fix.type_aux = 0; m2info->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; } { struct my_timming mt; unsigned int pos; int out; int cnt; matroxfb_var2my(&m2info->fbcon.var, &mt); mt.crtc = MATROXFB_SRC_CRTC2; /* CRTC2 delay */ mt.delay = 34; pos = (m2info->fbcon.var.yoffset * m2info->fbcon.var.xres_virtual + m2info->fbcon.var.xoffset) * m2info->fbcon.var.bits_per_pixel >> 3; pos += m2info->video.offbase; cnt = 0; down_read(&ACCESS_FBINFO(altout).lock); for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) { cnt++; if (ACCESS_FBINFO(outputs[out]).output->compute) { ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt); } } } ACCESS_FBINFO(crtc2).pixclock = mt.pixclock; ACCESS_FBINFO(crtc2).mnp = mt.mnp; up_read(&ACCESS_FBINFO(altout).lock); if (cnt) { matroxfb_dh_restore(m2info, &mt, mode, pos); } else { matroxfb_dh_disable(m2info); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -