// SPDX-License-Identifier: GPL-2.0-only/* * * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> * * Portions Copyright (c) 2001 Matrox Graphics Inc. * * Version: 1.65 2002/08/14 * * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * * Contributors: "menion?" <menion@mindless.com> * Betatesting, fixes, ideas * * "Kurt Garloff" <garloff@suse.de> * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" <trini@kernel.crashing.org> * MTRR stuff, PPC cleanups, betatesting, fixes, ideas * * "Bibek Sahu" <scorpio@dodds.net> * Access device through readb|w|l and write b|w|l * Extensive debugging stuff * * "Daniel Haun" <haund@usa.net> * Testing, hardware cursor fixes * * "Scott Wood" <sawst46+@pitt.edu> * Fixes * * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> * Betatesting * * "Kelly French" <targon@hazmat.com> * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> * Betatesting, bug reporting * * "Pablo Bianucci" <pbian@pccp.com.ar> * Fixes, ideas, betatesting * * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> * Fixes, enhandcements, ideas, betatesting * * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> * PPC betatesting, PPC support, backward compatibility * * "Paul Womar" <Paul@pwomar.demon.co.uk> * "Owen Waller" <O.Waller@ee.qub.ac.uk> * PPC betatesting * * "Thomas Pornin" <pornin@bolet.ens.fr> * Alpha betatesting * * "Pieter van Leuven" <pvl@iae.nl> * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> * G100 testing * * "H. Peter Arvin" <hpa@transmeta.com> * Ideas * * "Cort Dougan" <cort@cs.nmt.edu> * CHRP fixes and PReP cleanup * * "Mark Vojkovich" <mvojkovi@ucsd.edu> * G400 support * * "Samuel Hocevar" <sam@via.ecp.fr> * Fixes * * "Anton Altaparmakov" <AntonA@bigfoot.com> * G400 MAX/non-MAX distinction * * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com> * memtype extension (needed for GXT130P RS/6000 adapter) * * "Uns Lider" <unslider@miranda.org> * G100 PLNWT fixes * * "Denis Zaitsev" <zzz@cd-club.ru> * Fixes * * "Mike Pieper" <mike@pieper-family.de> * TVOut enhandcements, V4L2 control interface. * * "Diego Biurrun" <diego@biurrun.de> * DFP testing * * (following author is not in any relation with this code, but his code * is included in this driver) * * Based on framebuffer driver for VBE 2.0 compliant graphic boards * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> * * (following author is not in any relation with this code, but his ideas * were used when writing this driver) * * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> * */ #include <linux/aperture.h>#include <linux/export.h>#include <linux/version.h> #include "matroxfb_base.h"#include "matroxfb_misc.h"#include "matroxfb_accel.h"#include "matroxfb_DAC1064.h"#include "matroxfb_Ti3026.h"#include "matroxfb_maven.h"#include "matroxfb_crtc2.h"#include "matroxfb_g450.h"#include <linux/matroxfb.h>#include <linux/interrupt.h>#include <linux/nvram.h>#include <linux/slab.h>#include <linux/uaccess.h> #ifdef CONFIG_PPC_PMAC#include <asm/machdep.h>static int default_vmode = VMODE_NVRAM;static int default_cmode = CMODE_NVRAM;#endif static void matroxfb_unregister_device(struct matrox_fb_info* minfo); /* --------------------------------------------------------------------- */ /* * card parameters */ /* --------------------------------------------------------------------- */ static struct fb_var_screeninfo vesafb_defined = { 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/ 0,0, /* virtual -> visible no offset */ 8, /* depth -> load bits_per_pixel */ 0, /* greyscale ? */ {0,0,0}, /* R */ {0,0,0}, /* G */ {0,0,0}, /* B */ {0,0,0}, /* transparency */ 0, /* standard pixel format */ FB_ACTIVATE_NOW, -1,-1, FB_ACCELF_TEXT, /* accel flags */ 39721L,48L,16L,33L,10L, 96L,2L,~0, /* No sync info */ FB_VMODE_NONINTERLACED,}; /* --------------------------------------------------------------------- */static void update_crtc2(struct matrox_fb_info *minfo, unsigned int pos){ struct matroxfb_dh_fb_info *info = minfo->crtc2.info; /* Make sure that displays are compatible */ if (info && (info->fbcon.var.bits_per_pixel == minfo->fbcon.var.bits_per_pixel) && (info->fbcon.var.xres_virtual == minfo->fbcon.var.xres_virtual) && (info->fbcon.var.green.length == minfo->fbcon.var.green.length) ) { switch (minfo->fbcon.var.bits_per_pixel) { case 16: case 32: pos = pos * 8; if (info->interlaced) { mga_outl(0x3C2C, pos); mga_outl(0x3C28, pos + minfo->fbcon.var.xres_virtual * minfo->fbcon.var.bits_per_pixel / 8); } else { mga_outl(0x3C28, pos); } break; } }} static void matroxfb_crtc1_panpos(struct matrox_fb_info *minfo){ if (minfo->crtc1.panpos >= 0) { unsigned long flags; int panpos; matroxfb_DAC_lock_irqsave(flags); panpos = minfo->crtc1.panpos; if (panpos >= 0) { unsigned int extvga_reg; minfo->crtc1.panpos = -1; /* No update pending anymore */ extvga_reg = mga_inb(M_EXTVGA_INDEX); mga_setr(M_EXTVGA_INDEX, 0x00, panpos); if (extvga_reg != 0x00) { mga_outb(M_EXTVGA_INDEX, extvga_reg); } } matroxfb_DAC_unlock_irqrestore(flags); }} static irqreturn_t matrox_irq(int irq, void *dev_id){ u_int32_t status; int handled = 0; struct matrox_fb_info *minfo = dev_id; status = mga_inl(M_STATUS); if (status & 0x20) { mga_outl(M_ICLEAR, 0x20); minfo->crtc1.vsync.cnt++; matroxfb_crtc1_panpos(minfo); wake_up_interruptible(&minfo->crtc1.vsync.wait); handled = 1; } if (status & 0x200) { mga_outl(M_ICLEAR, 0x200); minfo->crtc2.vsync.cnt++; wake_up_interruptible(&minfo->crtc2.vsync.wait); handled = 1; } return IRQ_RETVAL(handled);} int matroxfb_enable_irq(struct matrox_fb_info *minfo, int reenable){ u_int32_t bm; if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) bm = 0x220; else bm = 0x020; if (!test_and_set_bit(0, &minfo->irq_flags)) { if (request_irq(minfo->pcidev->irq, matrox_irq, IRQF_SHARED, "matroxfb", minfo)) { clear_bit(0, &minfo->irq_flags); return -EINVAL; } /* Clear any pending field interrupts */ mga_outl(M_ICLEAR, bm); mga_outl(M_IEN, mga_inl(M_IEN) | bm); } else if (reenable) { u_int32_t ien; ien = mga_inl(M_IEN); if ((ien & bm) != bm) { printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien); mga_outl(M_IEN, ien | bm); } } return 0;} static void matroxfb_disable_irq(struct matrox_fb_info *minfo){ if (test_and_clear_bit(0, &minfo->irq_flags)) { /* Flush pending pan-at-vbl request... */ matroxfb_crtc1_panpos(minfo); if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220); else mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20); free_irq(minfo->pcidev->irq, minfo); }} int matroxfb_wait_for_sync(struct matrox_fb_info *minfo, u_int32_t crtc){ struct matrox_vsync *vs; unsigned int cnt; int ret; switch (crtc) { case 0: vs = &minfo->crtc1.vsync; break; case 1: if (minfo->devflags.accelerator != FB_ACCEL_MATROX_MGAG400) { return -ENODEV; } vs = &minfo->crtc2.vsync; break; default: return -ENODEV; } ret = matroxfb_enable_irq(minfo, 0); if (ret) { return ret; } cnt = vs->cnt; ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10); if (ret < 0) { return ret; } if (ret == 0) { matroxfb_enable_irq(minfo, 1); return -ETIMEDOUT; } return 0;} /* --------------------------------------------------------------------- */ static void matrox_pan_var(struct matrox_fb_info *minfo, struct fb_var_screeninfo *var){ unsigned int pos; unsigned short p0, p1, p2; unsigned int p3; int vbl; unsigned long flags; CRITFLAGS DBG(__func__) if (minfo->dead) return; minfo->fbcon.var.xoffset = var->xoffset; minfo->fbcon.var.yoffset = var->yoffset; pos = (minfo->fbcon.var.yoffset * minfo->fbcon.var.xres_virtual + minfo->fbcon.var.xoffset) * minfo->curr.final_bppShift / 32; pos += minfo->curr.ydstorg.chunks; p0 = minfo->hw.CRTC[0x0D] = pos & 0xFF; p1 = minfo->hw.CRTC[0x0C] = (pos & 0xFF00) >> 8; p2 = minfo->hw.CRTCEXT[0] = (minfo->hw.CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); p3 = minfo->hw.CRTCEXT[8] = pos >> 21; /* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */ vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(minfo, 0) == 0); CRITBEGIN matroxfb_DAC_lock_irqsave(flags); mga_setr(M_CRTC_INDEX, 0x0D, p0); mga_setr(M_CRTC_INDEX, 0x0C, p1); if (minfo->devflags.support32MB) mga_setr(M_EXTVGA_INDEX, 0x08, p3); if (vbl) { minfo->crtc1.panpos = p2; } else { /* Abort any pending change */ minfo->crtc1.panpos = -1; mga_setr(M_EXTVGA_INDEX, 0x00, p2); } matroxfb_DAC_unlock_irqrestore(flags); update_crtc2(minfo, pos); CRITEND} static void matroxfb_remove(struct matrox_fb_info *minfo, int dummy){ /* Currently we are holding big kernel lock on all dead & usecount updates. * Destroy everything after all users release it. Especially do not unregister * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check * for device unplugged when in use. * In future we should point mmio.vbase & video.vbase somewhere where we can * write data without causing too much damage... */ minfo->dead = 1; if (minfo->usecount) { /* destroy it later */ return; } matroxfb_unregister_device(minfo); unregister_framebuffer(&minfo->fbcon); matroxfb_g450_shutdown(minfo); arch_phys_wc_del(minfo->wc_cookie); kfree(minfo);} /* * Open/Release the frame buffer device */ static int matroxfb_open(struct fb_info *info, int user){ struct matrox_fb_info *minfo = info2minfo(info); DBG_LOOP(__func__) if (minfo->dead) { return -ENXIO; } minfo->usecount++; if (user) { minfo->userusecount++; } return(0);} static int matroxfb_release(struct fb_info *info, int user){ struct matrox_fb_info *minfo = info2minfo(info); DBG_LOOP(__func__) if (user) { if (0 == --minfo->userusecount) { matroxfb_disable_irq(minfo); } } if (!(--minfo->usecount) && minfo->dead) { matroxfb_remove(minfo, 0); } return(0);} static int matroxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) { struct matrox_fb_info *minfo = info2minfo(info); DBG(__func__) matrox_pan_var(minfo, var); return 0;} static int matroxfb_get_final_bppShift(const struct matrox_fb_info *minfo, int bpp){ int bppshft2; DBG(__func__) bppshft2 = bpp; if (!bppshft2) { return 8; } if (isInterleave(minfo)) bppshft2 >>= 1; if (minfo->devflags.video64bits) bppshft2 >>= 1; return bppshft2;} static int matroxfb_test_and_set_rounding(const struct matrox_fb_info *minfo, int xres, int bpp){ int over; int rounding; DBG(__func__) switch (bpp) { case 0: return xres; case 4: rounding = 128; break; case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */ break; case 16: rounding = 32; break; case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */ break; default: rounding = 16; /* on G400, 16 really does not work */ if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) rounding = 32; break; } if (isInterleave(minfo)) { rounding *= 2; } over = xres % rounding; if (over) xres += rounding-over; return xres;} static int matroxfb_pitch_adjust(const struct matrox_fb_info *minfo, int xres, int bpp){ const int* width; int xres_new; DBG(__func__) if (!bpp) return xres; width = minfo->capable.vxres; if (minfo->devflags.precise_width) { while (*width) { if ((*width >= xres) && (matroxfb_test_and_set_rounding(minfo, *width, bpp) == *width)) { break; } width++; } xres_new = *width; } else { xres_new = matroxfb_test_and_set_rounding(minfo, xres, bpp); }Lines 1–500 of 2598. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 * * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> * * Portions Copyright (c) 2001 Matrox Graphics Inc. * * Version: 1.65 2002/08/14 * * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> * * Contributors: "menion?" <menion@mindless.com> * Betatesting, fixes, ideas * * "Kurt Garloff" <garloff@suse.de> * Betatesting, fixes, ideas, videomodes, videomodes timmings * * "Tom Rini" <trini@kernel.crashing.org> * MTRR stuff, PPC cleanups, betatesting, fixes, ideas * * "Bibek Sahu" <scorpio@dodds.net> * Access device through readb|w|l and write b|w|l * Extensive debugging stuff * * "Daniel Haun" <haund@usa.net> * Testing, hardware cursor fixes * * "Scott Wood" <sawst46+@pitt.edu> * Fixes * * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> * Betatesting * * "Kelly French" <targon@hazmat.com> * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> * Betatesting, bug reporting * * "Pablo Bianucci" <pbian@pccp.com.ar> * Fixes, ideas, betatesting * * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> * Fixes, enhandcements, ideas, betatesting * * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> * PPC betatesting, PPC support, backward compatibility * * "Paul Womar" <Paul@pwomar.demon.co.uk> * "Owen Waller" <O.Waller@ee.qub.ac.uk> * PPC betatesting * * "Thomas Pornin" <pornin@bolet.ens.fr> * Alpha betatesting * * "Pieter van Leuven" <pvl@iae.nl> * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> * G100 testing * * "H. Peter Arvin" <hpa@transmeta.com> * Ideas * * "Cort Dougan" <cort@cs.nmt.edu> * CHRP fixes and PReP cleanup * * "Mark Vojkovich" <mvojkovi@ucsd.edu> * G400 support * * "Samuel Hocevar" <sam@via.ecp.fr> * Fixes * * "Anton Altaparmakov" <AntonA@bigfoot.com> * G400 MAX/non-MAX distinction * * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com> * memtype extension (needed for GXT130P RS/6000 adapter) * * "Uns Lider" <unslider@miranda.org> * G100 PLNWT fixes * * "Denis Zaitsev" <zzz@cd-club.ru> * Fixes * * "Mike Pieper" <mike@pieper-family.de> * TVOut enhandcements, V4L2 control interface. * * "Diego Biurrun" <diego@biurrun.de> * DFP testing * * (following author is not in any relation with this code, but his code * is included in this driver) * * Based on framebuffer driver for VBE 2.0 compliant graphic boards * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> * * (following author is not in any relation with this code, but his ideas * were used when writing this driver) * * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> * */ #include <linux/aperture.h> #include <linux/export.h> #include <linux/version.h> #include "matroxfb_base.h" #include "matroxfb_misc.h" #include "matroxfb_accel.h" #include "matroxfb_DAC1064.h" #include "matroxfb_Ti3026.h" #include "matroxfb_maven.h" #include "matroxfb_crtc2.h" #include "matroxfb_g450.h" #include <linux/matroxfb.h> #include <linux/interrupt.h> #include <linux/nvram.h> #include <linux/slab.h> #include <linux/uaccess.h> #ifdef CONFIG_PPC_PMAC #include <asm/machdep.h> static int default_vmode = VMODE_NVRAM; static int default_cmode = CMODE_NVRAM; #endif static void matroxfb_unregister_device(struct matrox_fb_info* minfo); /* --------------------------------------------------------------------- */ /* * card parameters */ /* --------------------------------------------------------------------- */ static struct fb_var_screeninfo vesafb_defined = { 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/ 0,0, /* virtual -> visible no offset */ 8, /* depth -> load bits_per_pixel */ 0, /* greyscale ? */ {0,0,0}, /* R */ {0,0,0}, /* G */ {0,0,0}, /* B */ {0,0,0}, /* transparency */ 0, /* standard pixel format */ FB_ACTIVATE_NOW, -1,-1, FB_ACCELF_TEXT, /* accel flags */ 39721L,48L,16L,33L,10L, 96L,2L,~0, /* No sync info */ FB_VMODE_NONINTERLACED, }; /* --------------------------------------------------------------------- */ static void update_crtc2(struct matrox_fb_info *minfo, unsigned int pos) { struct matroxfb_dh_fb_info *info = minfo->crtc2.info; /* Make sure that displays are compatible */ if (info && (info->fbcon.var.bits_per_pixel == minfo->fbcon.var.bits_per_pixel) && (info->fbcon.var.xres_virtual == minfo->fbcon.var.xres_virtual) && (info->fbcon.var.green.length == minfo->fbcon.var.green.length) ) { switch (minfo->fbcon.var.bits_per_pixel) { case 16: case 32: pos = pos * 8; if (info->interlaced) { mga_outl(0x3C2C, pos); mga_outl(0x3C28, pos + minfo->fbcon.var.xres_virtual * minfo->fbcon.var.bits_per_pixel / 8); } else { mga_outl(0x3C28, pos); } break; } } } static void matroxfb_crtc1_panpos(struct matrox_fb_info *minfo) { if (minfo->crtc1.panpos >= 0) { unsigned long flags; int panpos; matroxfb_DAC_lock_irqsave(flags); panpos = minfo->crtc1.panpos; if (panpos >= 0) { unsigned int extvga_reg; minfo->crtc1.panpos = -1; /* No update pending anymore */ extvga_reg = mga_inb(M_EXTVGA_INDEX); mga_setr(M_EXTVGA_INDEX, 0x00, panpos); if (extvga_reg != 0x00) { mga_outb(M_EXTVGA_INDEX, extvga_reg); } } matroxfb_DAC_unlock_irqrestore(flags); } } static irqreturn_t matrox_irq(int irq, void *dev_id) { u_int32_t status; int handled = 0; struct matrox_fb_info *minfo = dev_id; status = mga_inl(M_STATUS); if (status & 0x20) { mga_outl(M_ICLEAR, 0x20); minfo->crtc1.vsync.cnt++; matroxfb_crtc1_panpos(minfo); wake_up_interruptible(&minfo->crtc1.vsync.wait); handled = 1; } if (status & 0x200) { mga_outl(M_ICLEAR, 0x200); minfo->crtc2.vsync.cnt++; wake_up_interruptible(&minfo->crtc2.vsync.wait); handled = 1; } return IRQ_RETVAL(handled); } int matroxfb_enable_irq(struct matrox_fb_info *minfo, int reenable) { u_int32_t bm; if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) bm = 0x220; else bm = 0x020; if (!test_and_set_bit(0, &minfo->irq_flags)) { if (request_irq(minfo->pcidev->irq, matrox_irq, IRQF_SHARED, "matroxfb", minfo)) { clear_bit(0, &minfo->irq_flags); return -EINVAL; } /* Clear any pending field interrupts */ mga_outl(M_ICLEAR, bm); mga_outl(M_IEN, mga_inl(M_IEN) | bm); } else if (reenable) { u_int32_t ien; ien = mga_inl(M_IEN); if ((ien & bm) != bm) { printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien); mga_outl(M_IEN, ien | bm); } } return 0; } static void matroxfb_disable_irq(struct matrox_fb_info *minfo) { if (test_and_clear_bit(0, &minfo->irq_flags)) { /* Flush pending pan-at-vbl request... */ matroxfb_crtc1_panpos(minfo); if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220); else mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20); free_irq(minfo->pcidev->irq, minfo); } } int matroxfb_wait_for_sync(struct matrox_fb_info *minfo, u_int32_t crtc) { struct matrox_vsync *vs; unsigned int cnt; int ret; switch (crtc) { case 0: vs = &minfo->crtc1.vsync; break; case 1: if (minfo->devflags.accelerator != FB_ACCEL_MATROX_MGAG400) { return -ENODEV; } vs = &minfo->crtc2.vsync; break; default: return -ENODEV; } ret = matroxfb_enable_irq(minfo, 0); if (ret) { return ret; } cnt = vs->cnt; ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10); if (ret < 0) { return ret; } if (ret == 0) { matroxfb_enable_irq(minfo, 1); return -ETIMEDOUT; } return 0; } /* --------------------------------------------------------------------- */ static void matrox_pan_var(struct matrox_fb_info *minfo, struct fb_var_screeninfo *var) { unsigned int pos; unsigned short p0, p1, p2; unsigned int p3; int vbl; unsigned long flags; CRITFLAGS DBG(__func__) if (minfo->dead) return; minfo->fbcon.var.xoffset = var->xoffset; minfo->fbcon.var.yoffset = var->yoffset; pos = (minfo->fbcon.var.yoffset * minfo->fbcon.var.xres_virtual + minfo->fbcon.var.xoffset) * minfo->curr.final_bppShift / 32; pos += minfo->curr.ydstorg.chunks; p0 = minfo->hw.CRTC[0x0D] = pos & 0xFF; p1 = minfo->hw.CRTC[0x0C] = (pos & 0xFF00) >> 8; p2 = minfo->hw.CRTCEXT[0] = (minfo->hw.CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); p3 = minfo->hw.CRTCEXT[8] = pos >> 21; /* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */ vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(minfo, 0) == 0); CRITBEGIN matroxfb_DAC_lock_irqsave(flags); mga_setr(M_CRTC_INDEX, 0x0D, p0); mga_setr(M_CRTC_INDEX, 0x0C, p1); if (minfo->devflags.support32MB) mga_setr(M_EXTVGA_INDEX, 0x08, p3); if (vbl) { minfo->crtc1.panpos = p2; } else { /* Abort any pending change */ minfo->crtc1.panpos = -1; mga_setr(M_EXTVGA_INDEX, 0x00, p2); } matroxfb_DAC_unlock_irqrestore(flags); update_crtc2(minfo, pos); CRITEND } static void matroxfb_remove(struct matrox_fb_info *minfo, int dummy) { /* Currently we are holding big kernel lock on all dead & usecount updates. * Destroy everything after all users release it. Especially do not unregister * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check * for device unplugged when in use. * In future we should point mmio.vbase & video.vbase somewhere where we can * write data without causing too much damage... */ minfo->dead = 1; if (minfo->usecount) { /* destroy it later */ return; } matroxfb_unregister_device(minfo); unregister_framebuffer(&minfo->fbcon); matroxfb_g450_shutdown(minfo); arch_phys_wc_del(minfo->wc_cookie); kfree(minfo); } /* * Open/Release the frame buffer device */ static int matroxfb_open(struct fb_info *info, int user) { struct matrox_fb_info *minfo = info2minfo(info); DBG_LOOP(__func__) if (minfo->dead) { return -ENXIO; } minfo->usecount++; if (user) { minfo->userusecount++; } return(0); } static int matroxfb_release(struct fb_info *info, int user) { struct matrox_fb_info *minfo = info2minfo(info); DBG_LOOP(__func__) if (user) { if (0 == --minfo->userusecount) { matroxfb_disable_irq(minfo); } } if (!(--minfo->usecount) && minfo->dead) { matroxfb_remove(minfo, 0); } return(0); } static int matroxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) { struct matrox_fb_info *minfo = info2minfo(info); DBG(__func__) matrox_pan_var(minfo, var); return 0; } static int matroxfb_get_final_bppShift(const struct matrox_fb_info *minfo, int bpp) { int bppshft2; DBG(__func__) bppshft2 = bpp; if (!bppshft2) { return 8; } if (isInterleave(minfo)) bppshft2 >>= 1; if (minfo->devflags.video64bits) bppshft2 >>= 1; return bppshft2; } static int matroxfb_test_and_set_rounding(const struct matrox_fb_info *minfo, int xres, int bpp) { int over; int rounding; DBG(__func__) switch (bpp) { case 0: return xres; case 4: rounding = 128; break; case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */ break; case 16: rounding = 32; break; case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */ break; default: rounding = 16; /* on G400, 16 really does not work */ if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) rounding = 32; break; } if (isInterleave(minfo)) { rounding *= 2; } over = xres % rounding; if (over) xres += rounding-over; return xres; } static int matroxfb_pitch_adjust(const struct matrox_fb_info *minfo, int xres, int bpp) { const int* width; int xres_new; DBG(__func__) if (!bpp) return xres; width = minfo->capable.vxres; if (minfo->devflags.precise_width) { while (*width) { if ((*width >= xres) && (matroxfb_test_and_set_rounding(minfo, *width, bpp) == *width)) { break; } width++; } xres_new = *width; } else { xres_new = matroxfb_test_and_set_rounding(minfo, xres, bpp); }