162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Portions Copyright (c) 2001 Matrox Graphics Inc. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Version: 1.65 2002/08/14 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Contributors: "menion?" <menion@mindless.com> 1562306a36Sopenharmony_ci * Betatesting, fixes, ideas 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * "Kurt Garloff" <garloff@suse.de> 1862306a36Sopenharmony_ci * Betatesting, fixes, ideas, videomodes, videomodes timmings 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * "Tom Rini" <trini@kernel.crashing.org> 2162306a36Sopenharmony_ci * MTRR stuff, PPC cleanups, betatesting, fixes, ideas 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * "Bibek Sahu" <scorpio@dodds.net> 2462306a36Sopenharmony_ci * Access device through readb|w|l and write b|w|l 2562306a36Sopenharmony_ci * Extensive debugging stuff 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * "Daniel Haun" <haund@usa.net> 2862306a36Sopenharmony_ci * Testing, hardware cursor fixes 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * "Scott Wood" <sawst46+@pitt.edu> 3162306a36Sopenharmony_ci * Fixes 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> 3462306a36Sopenharmony_ci * Betatesting 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * "Kelly French" <targon@hazmat.com> 3762306a36Sopenharmony_ci * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> 3862306a36Sopenharmony_ci * Betatesting, bug reporting 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * "Pablo Bianucci" <pbian@pccp.com.ar> 4162306a36Sopenharmony_ci * Fixes, ideas, betatesting 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> 4462306a36Sopenharmony_ci * Fixes, enhandcements, ideas, betatesting 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> 4762306a36Sopenharmony_ci * PPC betatesting, PPC support, backward compatibility 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * "Paul Womar" <Paul@pwomar.demon.co.uk> 5062306a36Sopenharmony_ci * "Owen Waller" <O.Waller@ee.qub.ac.uk> 5162306a36Sopenharmony_ci * PPC betatesting 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * "Thomas Pornin" <pornin@bolet.ens.fr> 5462306a36Sopenharmony_ci * Alpha betatesting 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * "Pieter van Leuven" <pvl@iae.nl> 5762306a36Sopenharmony_ci * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> 5862306a36Sopenharmony_ci * G100 testing 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * "H. Peter Arvin" <hpa@transmeta.com> 6162306a36Sopenharmony_ci * Ideas 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * "Cort Dougan" <cort@cs.nmt.edu> 6462306a36Sopenharmony_ci * CHRP fixes and PReP cleanup 6562306a36Sopenharmony_ci * 6662306a36Sopenharmony_ci * "Mark Vojkovich" <mvojkovi@ucsd.edu> 6762306a36Sopenharmony_ci * G400 support 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * "Samuel Hocevar" <sam@via.ecp.fr> 7062306a36Sopenharmony_ci * Fixes 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * "Anton Altaparmakov" <AntonA@bigfoot.com> 7362306a36Sopenharmony_ci * G400 MAX/non-MAX distinction 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com> 7662306a36Sopenharmony_ci * memtype extension (needed for GXT130P RS/6000 adapter) 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * "Uns Lider" <unslider@miranda.org> 7962306a36Sopenharmony_ci * G100 PLNWT fixes 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * "Denis Zaitsev" <zzz@cd-club.ru> 8262306a36Sopenharmony_ci * Fixes 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * "Mike Pieper" <mike@pieper-family.de> 8562306a36Sopenharmony_ci * TVOut enhandcements, V4L2 control interface. 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * "Diego Biurrun" <diego@biurrun.de> 8862306a36Sopenharmony_ci * DFP testing 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * (following author is not in any relation with this code, but his code 9162306a36Sopenharmony_ci * is included in this driver) 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * Based on framebuffer driver for VBE 2.0 compliant graphic boards 9462306a36Sopenharmony_ci * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * (following author is not in any relation with this code, but his ideas 9762306a36Sopenharmony_ci * were used when writing this driver) 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#include <linux/aperture.h> 10462306a36Sopenharmony_ci#include <linux/version.h> 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#include "matroxfb_base.h" 10762306a36Sopenharmony_ci#include "matroxfb_misc.h" 10862306a36Sopenharmony_ci#include "matroxfb_accel.h" 10962306a36Sopenharmony_ci#include "matroxfb_DAC1064.h" 11062306a36Sopenharmony_ci#include "matroxfb_Ti3026.h" 11162306a36Sopenharmony_ci#include "matroxfb_maven.h" 11262306a36Sopenharmony_ci#include "matroxfb_crtc2.h" 11362306a36Sopenharmony_ci#include "matroxfb_g450.h" 11462306a36Sopenharmony_ci#include <linux/matroxfb.h> 11562306a36Sopenharmony_ci#include <linux/interrupt.h> 11662306a36Sopenharmony_ci#include <linux/nvram.h> 11762306a36Sopenharmony_ci#include <linux/slab.h> 11862306a36Sopenharmony_ci#include <linux/uaccess.h> 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 12162306a36Sopenharmony_ci#include <asm/machdep.h> 12262306a36Sopenharmony_cistatic int default_vmode = VMODE_NVRAM; 12362306a36Sopenharmony_cistatic int default_cmode = CMODE_NVRAM; 12462306a36Sopenharmony_ci#endif 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void matroxfb_unregister_device(struct matrox_fb_info* minfo); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* 13162306a36Sopenharmony_ci * card parameters 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic struct fb_var_screeninfo vesafb_defined = { 13762306a36Sopenharmony_ci 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/ 13862306a36Sopenharmony_ci 0,0, /* virtual -> visible no offset */ 13962306a36Sopenharmony_ci 8, /* depth -> load bits_per_pixel */ 14062306a36Sopenharmony_ci 0, /* greyscale ? */ 14162306a36Sopenharmony_ci {0,0,0}, /* R */ 14262306a36Sopenharmony_ci {0,0,0}, /* G */ 14362306a36Sopenharmony_ci {0,0,0}, /* B */ 14462306a36Sopenharmony_ci {0,0,0}, /* transparency */ 14562306a36Sopenharmony_ci 0, /* standard pixel format */ 14662306a36Sopenharmony_ci FB_ACTIVATE_NOW, 14762306a36Sopenharmony_ci -1,-1, 14862306a36Sopenharmony_ci FB_ACCELF_TEXT, /* accel flags */ 14962306a36Sopenharmony_ci 39721L,48L,16L,33L,10L, 15062306a36Sopenharmony_ci 96L,2L,~0, /* No sync info */ 15162306a36Sopenharmony_ci FB_VMODE_NONINTERLACED, 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 15762306a36Sopenharmony_cistatic void update_crtc2(struct matrox_fb_info *minfo, unsigned int pos) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct matroxfb_dh_fb_info *info = minfo->crtc2.info; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Make sure that displays are compatible */ 16262306a36Sopenharmony_ci if (info && (info->fbcon.var.bits_per_pixel == minfo->fbcon.var.bits_per_pixel) 16362306a36Sopenharmony_ci && (info->fbcon.var.xres_virtual == minfo->fbcon.var.xres_virtual) 16462306a36Sopenharmony_ci && (info->fbcon.var.green.length == minfo->fbcon.var.green.length) 16562306a36Sopenharmony_ci ) { 16662306a36Sopenharmony_ci switch (minfo->fbcon.var.bits_per_pixel) { 16762306a36Sopenharmony_ci case 16: 16862306a36Sopenharmony_ci case 32: 16962306a36Sopenharmony_ci pos = pos * 8; 17062306a36Sopenharmony_ci if (info->interlaced) { 17162306a36Sopenharmony_ci mga_outl(0x3C2C, pos); 17262306a36Sopenharmony_ci mga_outl(0x3C28, pos + minfo->fbcon.var.xres_virtual * minfo->fbcon.var.bits_per_pixel / 8); 17362306a36Sopenharmony_ci } else { 17462306a36Sopenharmony_ci mga_outl(0x3C28, pos); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void matroxfb_crtc1_panpos(struct matrox_fb_info *minfo) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci if (minfo->crtc1.panpos >= 0) { 18462306a36Sopenharmony_ci unsigned long flags; 18562306a36Sopenharmony_ci int panpos; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci matroxfb_DAC_lock_irqsave(flags); 18862306a36Sopenharmony_ci panpos = minfo->crtc1.panpos; 18962306a36Sopenharmony_ci if (panpos >= 0) { 19062306a36Sopenharmony_ci unsigned int extvga_reg; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci minfo->crtc1.panpos = -1; /* No update pending anymore */ 19362306a36Sopenharmony_ci extvga_reg = mga_inb(M_EXTVGA_INDEX); 19462306a36Sopenharmony_ci mga_setr(M_EXTVGA_INDEX, 0x00, panpos); 19562306a36Sopenharmony_ci if (extvga_reg != 0x00) { 19662306a36Sopenharmony_ci mga_outb(M_EXTVGA_INDEX, extvga_reg); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci matroxfb_DAC_unlock_irqrestore(flags); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic irqreturn_t matrox_irq(int irq, void *dev_id) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci u_int32_t status; 20662306a36Sopenharmony_ci int handled = 0; 20762306a36Sopenharmony_ci struct matrox_fb_info *minfo = dev_id; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci status = mga_inl(M_STATUS); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (status & 0x20) { 21262306a36Sopenharmony_ci mga_outl(M_ICLEAR, 0x20); 21362306a36Sopenharmony_ci minfo->crtc1.vsync.cnt++; 21462306a36Sopenharmony_ci matroxfb_crtc1_panpos(minfo); 21562306a36Sopenharmony_ci wake_up_interruptible(&minfo->crtc1.vsync.wait); 21662306a36Sopenharmony_ci handled = 1; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci if (status & 0x200) { 21962306a36Sopenharmony_ci mga_outl(M_ICLEAR, 0x200); 22062306a36Sopenharmony_ci minfo->crtc2.vsync.cnt++; 22162306a36Sopenharmony_ci wake_up_interruptible(&minfo->crtc2.vsync.wait); 22262306a36Sopenharmony_ci handled = 1; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci return IRQ_RETVAL(handled); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciint matroxfb_enable_irq(struct matrox_fb_info *minfo, int reenable) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci u_int32_t bm; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) 23262306a36Sopenharmony_ci bm = 0x220; 23362306a36Sopenharmony_ci else 23462306a36Sopenharmony_ci bm = 0x020; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (!test_and_set_bit(0, &minfo->irq_flags)) { 23762306a36Sopenharmony_ci if (request_irq(minfo->pcidev->irq, matrox_irq, 23862306a36Sopenharmony_ci IRQF_SHARED, "matroxfb", minfo)) { 23962306a36Sopenharmony_ci clear_bit(0, &minfo->irq_flags); 24062306a36Sopenharmony_ci return -EINVAL; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci /* Clear any pending field interrupts */ 24362306a36Sopenharmony_ci mga_outl(M_ICLEAR, bm); 24462306a36Sopenharmony_ci mga_outl(M_IEN, mga_inl(M_IEN) | bm); 24562306a36Sopenharmony_ci } else if (reenable) { 24662306a36Sopenharmony_ci u_int32_t ien; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ien = mga_inl(M_IEN); 24962306a36Sopenharmony_ci if ((ien & bm) != bm) { 25062306a36Sopenharmony_ci printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien); 25162306a36Sopenharmony_ci mga_outl(M_IEN, ien | bm); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic void matroxfb_disable_irq(struct matrox_fb_info *minfo) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci if (test_and_clear_bit(0, &minfo->irq_flags)) { 26062306a36Sopenharmony_ci /* Flush pending pan-at-vbl request... */ 26162306a36Sopenharmony_ci matroxfb_crtc1_panpos(minfo); 26262306a36Sopenharmony_ci if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) 26362306a36Sopenharmony_ci mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220); 26462306a36Sopenharmony_ci else 26562306a36Sopenharmony_ci mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20); 26662306a36Sopenharmony_ci free_irq(minfo->pcidev->irq, minfo); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciint matroxfb_wait_for_sync(struct matrox_fb_info *minfo, u_int32_t crtc) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct matrox_vsync *vs; 27362306a36Sopenharmony_ci unsigned int cnt; 27462306a36Sopenharmony_ci int ret; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci switch (crtc) { 27762306a36Sopenharmony_ci case 0: 27862306a36Sopenharmony_ci vs = &minfo->crtc1.vsync; 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci case 1: 28162306a36Sopenharmony_ci if (minfo->devflags.accelerator != FB_ACCEL_MATROX_MGAG400) { 28262306a36Sopenharmony_ci return -ENODEV; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci vs = &minfo->crtc2.vsync; 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci default: 28762306a36Sopenharmony_ci return -ENODEV; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci ret = matroxfb_enable_irq(minfo, 0); 29062306a36Sopenharmony_ci if (ret) { 29162306a36Sopenharmony_ci return ret; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci cnt = vs->cnt; 29562306a36Sopenharmony_ci ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10); 29662306a36Sopenharmony_ci if (ret < 0) { 29762306a36Sopenharmony_ci return ret; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci if (ret == 0) { 30062306a36Sopenharmony_ci matroxfb_enable_irq(minfo, 1); 30162306a36Sopenharmony_ci return -ETIMEDOUT; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci return 0; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void matrox_pan_var(struct matrox_fb_info *minfo, 30962306a36Sopenharmony_ci struct fb_var_screeninfo *var) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci unsigned int pos; 31262306a36Sopenharmony_ci unsigned short p0, p1, p2; 31362306a36Sopenharmony_ci unsigned int p3; 31462306a36Sopenharmony_ci int vbl; 31562306a36Sopenharmony_ci unsigned long flags; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci CRITFLAGS 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci DBG(__func__) 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (minfo->dead) 32262306a36Sopenharmony_ci return; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci minfo->fbcon.var.xoffset = var->xoffset; 32562306a36Sopenharmony_ci minfo->fbcon.var.yoffset = var->yoffset; 32662306a36Sopenharmony_ci pos = (minfo->fbcon.var.yoffset * minfo->fbcon.var.xres_virtual + minfo->fbcon.var.xoffset) * minfo->curr.final_bppShift / 32; 32762306a36Sopenharmony_ci pos += minfo->curr.ydstorg.chunks; 32862306a36Sopenharmony_ci p0 = minfo->hw.CRTC[0x0D] = pos & 0xFF; 32962306a36Sopenharmony_ci p1 = minfo->hw.CRTC[0x0C] = (pos & 0xFF00) >> 8; 33062306a36Sopenharmony_ci p2 = minfo->hw.CRTCEXT[0] = (minfo->hw.CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); 33162306a36Sopenharmony_ci p3 = minfo->hw.CRTCEXT[8] = pos >> 21; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */ 33462306a36Sopenharmony_ci vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(minfo, 0) == 0); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci CRITBEGIN 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci matroxfb_DAC_lock_irqsave(flags); 33962306a36Sopenharmony_ci mga_setr(M_CRTC_INDEX, 0x0D, p0); 34062306a36Sopenharmony_ci mga_setr(M_CRTC_INDEX, 0x0C, p1); 34162306a36Sopenharmony_ci if (minfo->devflags.support32MB) 34262306a36Sopenharmony_ci mga_setr(M_EXTVGA_INDEX, 0x08, p3); 34362306a36Sopenharmony_ci if (vbl) { 34462306a36Sopenharmony_ci minfo->crtc1.panpos = p2; 34562306a36Sopenharmony_ci } else { 34662306a36Sopenharmony_ci /* Abort any pending change */ 34762306a36Sopenharmony_ci minfo->crtc1.panpos = -1; 34862306a36Sopenharmony_ci mga_setr(M_EXTVGA_INDEX, 0x00, p2); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci matroxfb_DAC_unlock_irqrestore(flags); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci update_crtc2(minfo, pos); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci CRITEND 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void matroxfb_remove(struct matrox_fb_info *minfo, int dummy) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci /* Currently we are holding big kernel lock on all dead & usecount updates. 36062306a36Sopenharmony_ci * Destroy everything after all users release it. Especially do not unregister 36162306a36Sopenharmony_ci * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check 36262306a36Sopenharmony_ci * for device unplugged when in use. 36362306a36Sopenharmony_ci * In future we should point mmio.vbase & video.vbase somewhere where we can 36462306a36Sopenharmony_ci * write data without causing too much damage... 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci minfo->dead = 1; 36862306a36Sopenharmony_ci if (minfo->usecount) { 36962306a36Sopenharmony_ci /* destroy it later */ 37062306a36Sopenharmony_ci return; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci matroxfb_unregister_device(minfo); 37362306a36Sopenharmony_ci unregister_framebuffer(&minfo->fbcon); 37462306a36Sopenharmony_ci matroxfb_g450_shutdown(minfo); 37562306a36Sopenharmony_ci arch_phys_wc_del(minfo->wc_cookie); 37662306a36Sopenharmony_ci iounmap(minfo->mmio.vbase.vaddr); 37762306a36Sopenharmony_ci iounmap(minfo->video.vbase.vaddr); 37862306a36Sopenharmony_ci release_mem_region(minfo->video.base, minfo->video.len_maximum); 37962306a36Sopenharmony_ci release_mem_region(minfo->mmio.base, 16384); 38062306a36Sopenharmony_ci kfree(minfo); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* 38462306a36Sopenharmony_ci * Open/Release the frame buffer device 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int matroxfb_open(struct fb_info *info, int user) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci DBG_LOOP(__func__) 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (minfo->dead) { 39462306a36Sopenharmony_ci return -ENXIO; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci minfo->usecount++; 39762306a36Sopenharmony_ci if (user) { 39862306a36Sopenharmony_ci minfo->userusecount++; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci return(0); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int matroxfb_release(struct fb_info *info, int user) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci DBG_LOOP(__func__) 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (user) { 41062306a36Sopenharmony_ci if (0 == --minfo->userusecount) { 41162306a36Sopenharmony_ci matroxfb_disable_irq(minfo); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci if (!(--minfo->usecount) && minfo->dead) { 41562306a36Sopenharmony_ci matroxfb_remove(minfo, 0); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci return(0); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int matroxfb_pan_display(struct fb_var_screeninfo *var, 42162306a36Sopenharmony_ci struct fb_info* info) { 42262306a36Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci DBG(__func__) 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci matrox_pan_var(minfo, var); 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int matroxfb_get_final_bppShift(const struct matrox_fb_info *minfo, 43162306a36Sopenharmony_ci int bpp) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci int bppshft2; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci DBG(__func__) 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci bppshft2 = bpp; 43862306a36Sopenharmony_ci if (!bppshft2) { 43962306a36Sopenharmony_ci return 8; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci if (isInterleave(minfo)) 44262306a36Sopenharmony_ci bppshft2 >>= 1; 44362306a36Sopenharmony_ci if (minfo->devflags.video64bits) 44462306a36Sopenharmony_ci bppshft2 >>= 1; 44562306a36Sopenharmony_ci return bppshft2; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int matroxfb_test_and_set_rounding(const struct matrox_fb_info *minfo, 44962306a36Sopenharmony_ci int xres, int bpp) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci int over; 45262306a36Sopenharmony_ci int rounding; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci DBG(__func__) 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci switch (bpp) { 45762306a36Sopenharmony_ci case 0: return xres; 45862306a36Sopenharmony_ci case 4: rounding = 128; 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */ 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci case 16: rounding = 32; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */ 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci default: rounding = 16; 46762306a36Sopenharmony_ci /* on G400, 16 really does not work */ 46862306a36Sopenharmony_ci if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) 46962306a36Sopenharmony_ci rounding = 32; 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci if (isInterleave(minfo)) { 47362306a36Sopenharmony_ci rounding *= 2; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci over = xres % rounding; 47662306a36Sopenharmony_ci if (over) 47762306a36Sopenharmony_ci xres += rounding-over; 47862306a36Sopenharmony_ci return xres; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int matroxfb_pitch_adjust(const struct matrox_fb_info *minfo, int xres, 48262306a36Sopenharmony_ci int bpp) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci const int* width; 48562306a36Sopenharmony_ci int xres_new; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci DBG(__func__) 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (!bpp) return xres; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci width = minfo->capable.vxres; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (minfo->devflags.precise_width) { 49462306a36Sopenharmony_ci while (*width) { 49562306a36Sopenharmony_ci if ((*width >= xres) && (matroxfb_test_and_set_rounding(minfo, *width, bpp) == *width)) { 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci width++; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci xres_new = *width; 50162306a36Sopenharmony_ci } else { 50262306a36Sopenharmony_ci xres_new = matroxfb_test_and_set_rounding(minfo, xres, bpp); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci return xres_new; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci DBG(__func__) 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci switch (var->bits_per_pixel) { 51262306a36Sopenharmony_ci case 4: 51362306a36Sopenharmony_ci return 16; /* pseudocolor... 16 entries HW palette */ 51462306a36Sopenharmony_ci case 8: 51562306a36Sopenharmony_ci return 256; /* pseudocolor... 256 entries HW palette */ 51662306a36Sopenharmony_ci case 16: 51762306a36Sopenharmony_ci return 16; /* directcolor... 16 entries SW palette */ 51862306a36Sopenharmony_ci /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ 51962306a36Sopenharmony_ci case 24: 52062306a36Sopenharmony_ci return 16; /* directcolor... 16 entries SW palette */ 52162306a36Sopenharmony_ci /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ 52262306a36Sopenharmony_ci case 32: 52362306a36Sopenharmony_ci return 16; /* directcolor... 16 entries SW palette */ 52462306a36Sopenharmony_ci /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci return 16; /* return something reasonable... or panic()? */ 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int matroxfb_decode_var(const struct matrox_fb_info *minfo, 53062306a36Sopenharmony_ci struct fb_var_screeninfo *var, int *visual, 53162306a36Sopenharmony_ci int *video_cmap_len, unsigned int* ydstorg) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct RGBT { 53462306a36Sopenharmony_ci unsigned char bpp; 53562306a36Sopenharmony_ci struct { 53662306a36Sopenharmony_ci unsigned char offset, 53762306a36Sopenharmony_ci length; 53862306a36Sopenharmony_ci } red, 53962306a36Sopenharmony_ci green, 54062306a36Sopenharmony_ci blue, 54162306a36Sopenharmony_ci transp; 54262306a36Sopenharmony_ci signed char visual; 54362306a36Sopenharmony_ci }; 54462306a36Sopenharmony_ci static const struct RGBT table[]= { 54562306a36Sopenharmony_ci { 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR}, 54662306a36Sopenharmony_ci {15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR}, 54762306a36Sopenharmony_ci {16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR}, 54862306a36Sopenharmony_ci {24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR}, 54962306a36Sopenharmony_ci {32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR} 55062306a36Sopenharmony_ci }; 55162306a36Sopenharmony_ci struct RGBT const *rgbt; 55262306a36Sopenharmony_ci unsigned int bpp = var->bits_per_pixel; 55362306a36Sopenharmony_ci unsigned int vramlen; 55462306a36Sopenharmony_ci unsigned int memlen; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci DBG(__func__) 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci switch (bpp) { 55962306a36Sopenharmony_ci case 4: if (!minfo->capable.cfb4) return -EINVAL; 56062306a36Sopenharmony_ci break; 56162306a36Sopenharmony_ci case 8: break; 56262306a36Sopenharmony_ci case 16: break; 56362306a36Sopenharmony_ci case 24: break; 56462306a36Sopenharmony_ci case 32: break; 56562306a36Sopenharmony_ci default: return -EINVAL; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci *ydstorg = 0; 56862306a36Sopenharmony_ci vramlen = minfo->video.len_usable; 56962306a36Sopenharmony_ci if (var->yres_virtual < var->yres) 57062306a36Sopenharmony_ci var->yres_virtual = var->yres; 57162306a36Sopenharmony_ci if (var->xres_virtual < var->xres) 57262306a36Sopenharmony_ci var->xres_virtual = var->xres; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci var->xres_virtual = matroxfb_pitch_adjust(minfo, var->xres_virtual, bpp); 57562306a36Sopenharmony_ci memlen = var->xres_virtual * bpp * var->yres_virtual / 8; 57662306a36Sopenharmony_ci if (memlen > vramlen) { 57762306a36Sopenharmony_ci var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp); 57862306a36Sopenharmony_ci memlen = var->xres_virtual * bpp * var->yres_virtual / 8; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci /* There is hardware bug that no line can cross 4MB boundary */ 58162306a36Sopenharmony_ci /* give up for CFB24, it is impossible to easy workaround it */ 58262306a36Sopenharmony_ci /* for other try to do something */ 58362306a36Sopenharmony_ci if (!minfo->capable.cross4MB && (memlen > 0x400000)) { 58462306a36Sopenharmony_ci if (bpp == 24) { 58562306a36Sopenharmony_ci /* sorry */ 58662306a36Sopenharmony_ci } else { 58762306a36Sopenharmony_ci unsigned int linelen; 58862306a36Sopenharmony_ci unsigned int m1 = linelen = var->xres_virtual * bpp / 8; 58962306a36Sopenharmony_ci unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ 59062306a36Sopenharmony_ci unsigned int max_yres; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci while (m1) { 59362306a36Sopenharmony_ci while (m2 >= m1) m2 -= m1; 59462306a36Sopenharmony_ci swap(m1, m2); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci m2 = linelen * PAGE_SIZE / m2; 59762306a36Sopenharmony_ci *ydstorg = m2 = 0x400000 % m2; 59862306a36Sopenharmony_ci max_yres = (vramlen - m2) / linelen; 59962306a36Sopenharmony_ci if (var->yres_virtual > max_yres) 60062306a36Sopenharmony_ci var->yres_virtual = max_yres; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci /* YDSTLEN contains only signed 16bit value */ 60462306a36Sopenharmony_ci if (var->yres_virtual > 32767) 60562306a36Sopenharmony_ci var->yres_virtual = 32767; 60662306a36Sopenharmony_ci /* we must round yres/xres down, we already rounded y/xres_virtual up 60762306a36Sopenharmony_ci if it was possible. We should return -EINVAL, but I disagree */ 60862306a36Sopenharmony_ci if (var->yres_virtual < var->yres) 60962306a36Sopenharmony_ci var->yres = var->yres_virtual; 61062306a36Sopenharmony_ci if (var->xres_virtual < var->xres) 61162306a36Sopenharmony_ci var->xres = var->xres_virtual; 61262306a36Sopenharmony_ci if (var->xoffset + var->xres > var->xres_virtual) 61362306a36Sopenharmony_ci var->xoffset = var->xres_virtual - var->xres; 61462306a36Sopenharmony_ci if (var->yoffset + var->yres > var->yres_virtual) 61562306a36Sopenharmony_ci var->yoffset = var->yres_virtual - var->yres; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (bpp == 16 && var->green.length == 5) { 61862306a36Sopenharmony_ci bpp--; /* an artificial value - 15 */ 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci for (rgbt = table; rgbt->bpp < bpp; rgbt++); 62262306a36Sopenharmony_ci#define SETCLR(clr)\ 62362306a36Sopenharmony_ci var->clr.offset = rgbt->clr.offset;\ 62462306a36Sopenharmony_ci var->clr.length = rgbt->clr.length 62562306a36Sopenharmony_ci SETCLR(red); 62662306a36Sopenharmony_ci SETCLR(green); 62762306a36Sopenharmony_ci SETCLR(blue); 62862306a36Sopenharmony_ci SETCLR(transp); 62962306a36Sopenharmony_ci#undef SETCLR 63062306a36Sopenharmony_ci *visual = rgbt->visual; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (bpp > 8) 63362306a36Sopenharmony_ci dprintk("matroxfb: truecolor: " 63462306a36Sopenharmony_ci "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", 63562306a36Sopenharmony_ci var->transp.length, var->red.length, var->green.length, var->blue.length, 63662306a36Sopenharmony_ci var->transp.offset, var->red.offset, var->green.offset, var->blue.offset); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci *video_cmap_len = matroxfb_get_cmap_len(var); 63962306a36Sopenharmony_ci dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel, 64062306a36Sopenharmony_ci var->xres_virtual, var->yres_virtual); 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, 64562306a36Sopenharmony_ci unsigned blue, unsigned transp, 64662306a36Sopenharmony_ci struct fb_info *fb_info) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci DBG(__func__) 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci /* 65362306a36Sopenharmony_ci * Set a single color register. The values supplied are 65462306a36Sopenharmony_ci * already rounded down to the hardware's capabilities 65562306a36Sopenharmony_ci * (according to the entries in the `var' structure). Return 65662306a36Sopenharmony_ci * != 0 for invalid regno. 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (regno >= minfo->curr.cmap_len) 66062306a36Sopenharmony_ci return 1; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (minfo->fbcon.var.grayscale) { 66362306a36Sopenharmony_ci /* gray = 0.30*R + 0.59*G + 0.11*B */ 66462306a36Sopenharmony_ci red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci red = CNVT_TOHW(red, minfo->fbcon.var.red.length); 66862306a36Sopenharmony_ci green = CNVT_TOHW(green, minfo->fbcon.var.green.length); 66962306a36Sopenharmony_ci blue = CNVT_TOHW(blue, minfo->fbcon.var.blue.length); 67062306a36Sopenharmony_ci transp = CNVT_TOHW(transp, minfo->fbcon.var.transp.length); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci switch (minfo->fbcon.var.bits_per_pixel) { 67362306a36Sopenharmony_ci case 4: 67462306a36Sopenharmony_ci case 8: 67562306a36Sopenharmony_ci mga_outb(M_DAC_REG, regno); 67662306a36Sopenharmony_ci mga_outb(M_DAC_VAL, red); 67762306a36Sopenharmony_ci mga_outb(M_DAC_VAL, green); 67862306a36Sopenharmony_ci mga_outb(M_DAC_VAL, blue); 67962306a36Sopenharmony_ci break; 68062306a36Sopenharmony_ci case 16: 68162306a36Sopenharmony_ci if (regno >= 16) 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci { 68462306a36Sopenharmony_ci u_int16_t col = 68562306a36Sopenharmony_ci (red << minfo->fbcon.var.red.offset) | 68662306a36Sopenharmony_ci (green << minfo->fbcon.var.green.offset) | 68762306a36Sopenharmony_ci (blue << minfo->fbcon.var.blue.offset) | 68862306a36Sopenharmony_ci (transp << minfo->fbcon.var.transp.offset); /* for 1:5:5:5 */ 68962306a36Sopenharmony_ci minfo->cmap[regno] = col | (col << 16); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci case 24: 69362306a36Sopenharmony_ci case 32: 69462306a36Sopenharmony_ci if (regno >= 16) 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci minfo->cmap[regno] = 69762306a36Sopenharmony_ci (red << minfo->fbcon.var.red.offset) | 69862306a36Sopenharmony_ci (green << minfo->fbcon.var.green.offset) | 69962306a36Sopenharmony_ci (blue << minfo->fbcon.var.blue.offset) | 70062306a36Sopenharmony_ci (transp << minfo->fbcon.var.transp.offset); /* 8:8:8:8 */ 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic void matroxfb_init_fix(struct matrox_fb_info *minfo) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct fb_fix_screeninfo *fix = &minfo->fbcon.fix; 70962306a36Sopenharmony_ci DBG(__func__) 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci strcpy(fix->id,"MATROX"); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */ 71462306a36Sopenharmony_ci fix->ypanstep = 1; 71562306a36Sopenharmony_ci fix->ywrapstep = 0; 71662306a36Sopenharmony_ci fix->mmio_start = minfo->mmio.base; 71762306a36Sopenharmony_ci fix->mmio_len = minfo->mmio.len; 71862306a36Sopenharmony_ci fix->accel = minfo->devflags.accelerator; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void matroxfb_update_fix(struct matrox_fb_info *minfo) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct fb_fix_screeninfo *fix = &minfo->fbcon.fix; 72462306a36Sopenharmony_ci DBG(__func__) 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci mutex_lock(&minfo->fbcon.mm_lock); 72762306a36Sopenharmony_ci fix->smem_start = minfo->video.base + minfo->curr.ydstorg.bytes; 72862306a36Sopenharmony_ci fix->smem_len = minfo->video.len_usable - minfo->curr.ydstorg.bytes; 72962306a36Sopenharmony_ci mutex_unlock(&minfo->fbcon.mm_lock); 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci int err; 73562306a36Sopenharmony_ci int visual; 73662306a36Sopenharmony_ci int cmap_len; 73762306a36Sopenharmony_ci unsigned int ydstorg; 73862306a36Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (minfo->dead) { 74162306a36Sopenharmony_ci return -ENXIO; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci if ((err = matroxfb_decode_var(minfo, var, &visual, &cmap_len, &ydstorg)) != 0) 74462306a36Sopenharmony_ci return err; 74562306a36Sopenharmony_ci return 0; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic int matroxfb_set_par(struct fb_info *info) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci int err; 75162306a36Sopenharmony_ci int visual; 75262306a36Sopenharmony_ci int cmap_len; 75362306a36Sopenharmony_ci unsigned int ydstorg; 75462306a36Sopenharmony_ci struct fb_var_screeninfo *var; 75562306a36Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci DBG(__func__) 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (minfo->dead) { 76062306a36Sopenharmony_ci return -ENXIO; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci var = &info->var; 76462306a36Sopenharmony_ci if ((err = matroxfb_decode_var(minfo, var, &visual, &cmap_len, &ydstorg)) != 0) 76562306a36Sopenharmony_ci return err; 76662306a36Sopenharmony_ci minfo->fbcon.screen_base = vaddr_va(minfo->video.vbase) + ydstorg; 76762306a36Sopenharmony_ci matroxfb_update_fix(minfo); 76862306a36Sopenharmony_ci minfo->fbcon.fix.visual = visual; 76962306a36Sopenharmony_ci minfo->fbcon.fix.type = FB_TYPE_PACKED_PIXELS; 77062306a36Sopenharmony_ci minfo->fbcon.fix.type_aux = 0; 77162306a36Sopenharmony_ci minfo->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; 77262306a36Sopenharmony_ci { 77362306a36Sopenharmony_ci unsigned int pos; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci minfo->curr.cmap_len = cmap_len; 77662306a36Sopenharmony_ci ydstorg += minfo->devflags.ydstorg; 77762306a36Sopenharmony_ci minfo->curr.ydstorg.bytes = ydstorg; 77862306a36Sopenharmony_ci minfo->curr.ydstorg.chunks = ydstorg >> (isInterleave(minfo) ? 3 : 2); 77962306a36Sopenharmony_ci if (var->bits_per_pixel == 4) 78062306a36Sopenharmony_ci minfo->curr.ydstorg.pixels = ydstorg; 78162306a36Sopenharmony_ci else 78262306a36Sopenharmony_ci minfo->curr.ydstorg.pixels = (ydstorg * 8) / var->bits_per_pixel; 78362306a36Sopenharmony_ci minfo->curr.final_bppShift = matroxfb_get_final_bppShift(minfo, var->bits_per_pixel); 78462306a36Sopenharmony_ci { struct my_timming mt; 78562306a36Sopenharmony_ci struct matrox_hw_state* hw; 78662306a36Sopenharmony_ci int out; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci matroxfb_var2my(var, &mt); 78962306a36Sopenharmony_ci mt.crtc = MATROXFB_SRC_CRTC1; 79062306a36Sopenharmony_ci /* CRTC1 delays */ 79162306a36Sopenharmony_ci switch (var->bits_per_pixel) { 79262306a36Sopenharmony_ci case 0: mt.delay = 31 + 0; break; 79362306a36Sopenharmony_ci case 16: mt.delay = 21 + 8; break; 79462306a36Sopenharmony_ci case 24: mt.delay = 17 + 8; break; 79562306a36Sopenharmony_ci case 32: mt.delay = 16 + 8; break; 79662306a36Sopenharmony_ci default: mt.delay = 31 + 8; break; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci hw = &minfo->hw; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci down_read(&minfo->altout.lock); 80262306a36Sopenharmony_ci for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { 80362306a36Sopenharmony_ci if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 && 80462306a36Sopenharmony_ci minfo->outputs[out].output->compute) { 80562306a36Sopenharmony_ci minfo->outputs[out].output->compute(minfo->outputs[out].data, &mt); 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci up_read(&minfo->altout.lock); 80962306a36Sopenharmony_ci minfo->crtc1.pixclock = mt.pixclock; 81062306a36Sopenharmony_ci minfo->crtc1.mnp = mt.mnp; 81162306a36Sopenharmony_ci minfo->hw_switch->init(minfo, &mt); 81262306a36Sopenharmony_ci pos = (var->yoffset * var->xres_virtual + var->xoffset) * minfo->curr.final_bppShift / 32; 81362306a36Sopenharmony_ci pos += minfo->curr.ydstorg.chunks; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci hw->CRTC[0x0D] = pos & 0xFF; 81662306a36Sopenharmony_ci hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; 81762306a36Sopenharmony_ci hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); 81862306a36Sopenharmony_ci hw->CRTCEXT[8] = pos >> 21; 81962306a36Sopenharmony_ci minfo->hw_switch->restore(minfo); 82062306a36Sopenharmony_ci update_crtc2(minfo, pos); 82162306a36Sopenharmony_ci down_read(&minfo->altout.lock); 82262306a36Sopenharmony_ci for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { 82362306a36Sopenharmony_ci if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 && 82462306a36Sopenharmony_ci minfo->outputs[out].output->program) { 82562306a36Sopenharmony_ci minfo->outputs[out].output->program(minfo->outputs[out].data); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { 82962306a36Sopenharmony_ci if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 && 83062306a36Sopenharmony_ci minfo->outputs[out].output->start) { 83162306a36Sopenharmony_ci minfo->outputs[out].output->start(minfo->outputs[out].data); 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci up_read(&minfo->altout.lock); 83562306a36Sopenharmony_ci matrox_cfbX_init(minfo); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci minfo->initialized = 1; 83962306a36Sopenharmony_ci return 0; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cistatic int matroxfb_get_vblank(struct matrox_fb_info *minfo, 84362306a36Sopenharmony_ci struct fb_vblank *vblank) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci unsigned int sts1; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci matroxfb_enable_irq(minfo, 0); 84862306a36Sopenharmony_ci memset(vblank, 0, sizeof(*vblank)); 84962306a36Sopenharmony_ci vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC | 85062306a36Sopenharmony_ci FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK; 85162306a36Sopenharmony_ci sts1 = mga_inb(M_INSTS1); 85262306a36Sopenharmony_ci vblank->vcount = mga_inl(M_VCOUNT); 85362306a36Sopenharmony_ci /* BTW, on my PIII/450 with G400, reading M_INSTS1 85462306a36Sopenharmony_ci byte makes this call about 12% slower (1.70 vs. 2.05 us 85562306a36Sopenharmony_ci per ioctl()) */ 85662306a36Sopenharmony_ci if (sts1 & 1) 85762306a36Sopenharmony_ci vblank->flags |= FB_VBLANK_HBLANKING; 85862306a36Sopenharmony_ci if (sts1 & 8) 85962306a36Sopenharmony_ci vblank->flags |= FB_VBLANK_VSYNCING; 86062306a36Sopenharmony_ci if (vblank->vcount >= minfo->fbcon.var.yres) 86162306a36Sopenharmony_ci vblank->flags |= FB_VBLANK_VBLANKING; 86262306a36Sopenharmony_ci if (test_bit(0, &minfo->irq_flags)) { 86362306a36Sopenharmony_ci vblank->flags |= FB_VBLANK_HAVE_COUNT; 86462306a36Sopenharmony_ci /* Only one writer, aligned int value... 86562306a36Sopenharmony_ci it should work without lock and without atomic_t */ 86662306a36Sopenharmony_ci vblank->count = minfo->crtc1.vsync.cnt; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci return 0; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic struct matrox_altout panellink_output = { 87262306a36Sopenharmony_ci .name = "Panellink output", 87362306a36Sopenharmony_ci}; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic int matroxfb_ioctl(struct fb_info *info, 87662306a36Sopenharmony_ci unsigned int cmd, unsigned long arg) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 87962306a36Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci DBG(__func__) 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (minfo->dead) { 88462306a36Sopenharmony_ci return -ENXIO; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci switch (cmd) { 88862306a36Sopenharmony_ci case FBIOGET_VBLANK: 88962306a36Sopenharmony_ci { 89062306a36Sopenharmony_ci struct fb_vblank vblank; 89162306a36Sopenharmony_ci int err; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci err = matroxfb_get_vblank(minfo, &vblank); 89462306a36Sopenharmony_ci if (err) 89562306a36Sopenharmony_ci return err; 89662306a36Sopenharmony_ci if (copy_to_user(argp, &vblank, sizeof(vblank))) 89762306a36Sopenharmony_ci return -EFAULT; 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci case FBIO_WAITFORVSYNC: 90162306a36Sopenharmony_ci { 90262306a36Sopenharmony_ci u_int32_t crt; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (get_user(crt, (u_int32_t __user *)arg)) 90562306a36Sopenharmony_ci return -EFAULT; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci return matroxfb_wait_for_sync(minfo, crt); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci case MATROXFB_SET_OUTPUT_MODE: 91062306a36Sopenharmony_ci { 91162306a36Sopenharmony_ci struct matroxioc_output_mode mom; 91262306a36Sopenharmony_ci struct matrox_altout *oproc; 91362306a36Sopenharmony_ci int val; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (copy_from_user(&mom, argp, sizeof(mom))) 91662306a36Sopenharmony_ci return -EFAULT; 91762306a36Sopenharmony_ci if (mom.output >= MATROXFB_MAX_OUTPUTS) 91862306a36Sopenharmony_ci return -ENXIO; 91962306a36Sopenharmony_ci down_read(&minfo->altout.lock); 92062306a36Sopenharmony_ci oproc = minfo->outputs[mom.output].output; 92162306a36Sopenharmony_ci if (!oproc) { 92262306a36Sopenharmony_ci val = -ENXIO; 92362306a36Sopenharmony_ci } else if (!oproc->verifymode) { 92462306a36Sopenharmony_ci if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) { 92562306a36Sopenharmony_ci val = 0; 92662306a36Sopenharmony_ci } else { 92762306a36Sopenharmony_ci val = -EINVAL; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci } else { 93062306a36Sopenharmony_ci val = oproc->verifymode(minfo->outputs[mom.output].data, mom.mode); 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci if (!val) { 93362306a36Sopenharmony_ci if (minfo->outputs[mom.output].mode != mom.mode) { 93462306a36Sopenharmony_ci minfo->outputs[mom.output].mode = mom.mode; 93562306a36Sopenharmony_ci val = 1; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci up_read(&minfo->altout.lock); 93962306a36Sopenharmony_ci if (val != 1) 94062306a36Sopenharmony_ci return val; 94162306a36Sopenharmony_ci switch (minfo->outputs[mom.output].src) { 94262306a36Sopenharmony_ci case MATROXFB_SRC_CRTC1: 94362306a36Sopenharmony_ci matroxfb_set_par(info); 94462306a36Sopenharmony_ci break; 94562306a36Sopenharmony_ci case MATROXFB_SRC_CRTC2: 94662306a36Sopenharmony_ci { 94762306a36Sopenharmony_ci struct matroxfb_dh_fb_info* crtc2; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci down_read(&minfo->crtc2.lock); 95062306a36Sopenharmony_ci crtc2 = minfo->crtc2.info; 95162306a36Sopenharmony_ci if (crtc2) 95262306a36Sopenharmony_ci crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon); 95362306a36Sopenharmony_ci up_read(&minfo->crtc2.lock); 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci break; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci case MATROXFB_GET_OUTPUT_MODE: 96062306a36Sopenharmony_ci { 96162306a36Sopenharmony_ci struct matroxioc_output_mode mom; 96262306a36Sopenharmony_ci struct matrox_altout *oproc; 96362306a36Sopenharmony_ci int val; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (copy_from_user(&mom, argp, sizeof(mom))) 96662306a36Sopenharmony_ci return -EFAULT; 96762306a36Sopenharmony_ci if (mom.output >= MATROXFB_MAX_OUTPUTS) 96862306a36Sopenharmony_ci return -ENXIO; 96962306a36Sopenharmony_ci down_read(&minfo->altout.lock); 97062306a36Sopenharmony_ci oproc = minfo->outputs[mom.output].output; 97162306a36Sopenharmony_ci if (!oproc) { 97262306a36Sopenharmony_ci val = -ENXIO; 97362306a36Sopenharmony_ci } else { 97462306a36Sopenharmony_ci mom.mode = minfo->outputs[mom.output].mode; 97562306a36Sopenharmony_ci val = 0; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci up_read(&minfo->altout.lock); 97862306a36Sopenharmony_ci if (val) 97962306a36Sopenharmony_ci return val; 98062306a36Sopenharmony_ci if (copy_to_user(argp, &mom, sizeof(mom))) 98162306a36Sopenharmony_ci return -EFAULT; 98262306a36Sopenharmony_ci return 0; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci case MATROXFB_SET_OUTPUT_CONNECTION: 98562306a36Sopenharmony_ci { 98662306a36Sopenharmony_ci u_int32_t tmp; 98762306a36Sopenharmony_ci int i; 98862306a36Sopenharmony_ci int changes; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (copy_from_user(&tmp, argp, sizeof(tmp))) 99162306a36Sopenharmony_ci return -EFAULT; 99262306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 99362306a36Sopenharmony_ci if (tmp & (1 << i)) { 99462306a36Sopenharmony_ci if (i >= MATROXFB_MAX_OUTPUTS) 99562306a36Sopenharmony_ci return -ENXIO; 99662306a36Sopenharmony_ci if (!minfo->outputs[i].output) 99762306a36Sopenharmony_ci return -ENXIO; 99862306a36Sopenharmony_ci switch (minfo->outputs[i].src) { 99962306a36Sopenharmony_ci case MATROXFB_SRC_NONE: 100062306a36Sopenharmony_ci case MATROXFB_SRC_CRTC1: 100162306a36Sopenharmony_ci break; 100262306a36Sopenharmony_ci default: 100362306a36Sopenharmony_ci return -EBUSY; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci if (minfo->devflags.panellink) { 100862306a36Sopenharmony_ci if (tmp & MATROXFB_OUTPUT_CONN_DFP) { 100962306a36Sopenharmony_ci if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY) 101062306a36Sopenharmony_ci return -EINVAL; 101162306a36Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 101262306a36Sopenharmony_ci if (minfo->outputs[i].src == MATROXFB_SRC_CRTC2) { 101362306a36Sopenharmony_ci return -EBUSY; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci changes = 0; 101962306a36Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 102062306a36Sopenharmony_ci if (tmp & (1 << i)) { 102162306a36Sopenharmony_ci if (minfo->outputs[i].src != MATROXFB_SRC_CRTC1) { 102262306a36Sopenharmony_ci changes = 1; 102362306a36Sopenharmony_ci minfo->outputs[i].src = MATROXFB_SRC_CRTC1; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci } else if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) { 102662306a36Sopenharmony_ci changes = 1; 102762306a36Sopenharmony_ci minfo->outputs[i].src = MATROXFB_SRC_NONE; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci if (!changes) 103162306a36Sopenharmony_ci return 0; 103262306a36Sopenharmony_ci matroxfb_set_par(info); 103362306a36Sopenharmony_ci return 0; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci case MATROXFB_GET_OUTPUT_CONNECTION: 103662306a36Sopenharmony_ci { 103762306a36Sopenharmony_ci u_int32_t conn = 0; 103862306a36Sopenharmony_ci int i; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 104162306a36Sopenharmony_ci if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) { 104262306a36Sopenharmony_ci conn |= 1 << i; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci if (put_user(conn, (u_int32_t __user *)arg)) 104662306a36Sopenharmony_ci return -EFAULT; 104762306a36Sopenharmony_ci return 0; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci case MATROXFB_GET_AVAILABLE_OUTPUTS: 105062306a36Sopenharmony_ci { 105162306a36Sopenharmony_ci u_int32_t conn = 0; 105262306a36Sopenharmony_ci int i; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 105562306a36Sopenharmony_ci if (minfo->outputs[i].output) { 105662306a36Sopenharmony_ci switch (minfo->outputs[i].src) { 105762306a36Sopenharmony_ci case MATROXFB_SRC_NONE: 105862306a36Sopenharmony_ci case MATROXFB_SRC_CRTC1: 105962306a36Sopenharmony_ci conn |= 1 << i; 106062306a36Sopenharmony_ci break; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci if (minfo->devflags.panellink) { 106562306a36Sopenharmony_ci if (conn & MATROXFB_OUTPUT_CONN_DFP) 106662306a36Sopenharmony_ci conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY; 106762306a36Sopenharmony_ci if (conn & MATROXFB_OUTPUT_CONN_SECONDARY) 106862306a36Sopenharmony_ci conn &= ~MATROXFB_OUTPUT_CONN_DFP; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci if (put_user(conn, (u_int32_t __user *)arg)) 107162306a36Sopenharmony_ci return -EFAULT; 107262306a36Sopenharmony_ci return 0; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci case MATROXFB_GET_ALL_OUTPUTS: 107562306a36Sopenharmony_ci { 107662306a36Sopenharmony_ci u_int32_t conn = 0; 107762306a36Sopenharmony_ci int i; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 108062306a36Sopenharmony_ci if (minfo->outputs[i].output) { 108162306a36Sopenharmony_ci conn |= 1 << i; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci if (put_user(conn, (u_int32_t __user *)arg)) 108562306a36Sopenharmony_ci return -EFAULT; 108662306a36Sopenharmony_ci return 0; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci case VIDIOC_QUERYCAP: 108962306a36Sopenharmony_ci { 109062306a36Sopenharmony_ci struct v4l2_capability r; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci memset(&r, 0, sizeof(r)); 109362306a36Sopenharmony_ci strcpy(r.driver, "matroxfb"); 109462306a36Sopenharmony_ci strcpy(r.card, "Matrox"); 109562306a36Sopenharmony_ci sprintf(r.bus_info, "PCI:%s", pci_name(minfo->pcidev)); 109662306a36Sopenharmony_ci r.version = KERNEL_VERSION(1,0,0); 109762306a36Sopenharmony_ci r.capabilities = V4L2_CAP_VIDEO_OUTPUT; 109862306a36Sopenharmony_ci if (copy_to_user(argp, &r, sizeof(r))) 109962306a36Sopenharmony_ci return -EFAULT; 110062306a36Sopenharmony_ci return 0; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci case VIDIOC_QUERYCTRL: 110462306a36Sopenharmony_ci { 110562306a36Sopenharmony_ci struct v4l2_queryctrl qctrl; 110662306a36Sopenharmony_ci int err; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (copy_from_user(&qctrl, argp, sizeof(qctrl))) 110962306a36Sopenharmony_ci return -EFAULT; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci down_read(&minfo->altout.lock); 111262306a36Sopenharmony_ci if (!minfo->outputs[1].output) { 111362306a36Sopenharmony_ci err = -ENXIO; 111462306a36Sopenharmony_ci } else if (minfo->outputs[1].output->getqueryctrl) { 111562306a36Sopenharmony_ci err = minfo->outputs[1].output->getqueryctrl(minfo->outputs[1].data, &qctrl); 111662306a36Sopenharmony_ci } else { 111762306a36Sopenharmony_ci err = -EINVAL; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci up_read(&minfo->altout.lock); 112062306a36Sopenharmony_ci if (err >= 0 && 112162306a36Sopenharmony_ci copy_to_user(argp, &qctrl, sizeof(qctrl))) 112262306a36Sopenharmony_ci return -EFAULT; 112362306a36Sopenharmony_ci return err; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci case VIDIOC_G_CTRL: 112662306a36Sopenharmony_ci { 112762306a36Sopenharmony_ci struct v4l2_control ctrl; 112862306a36Sopenharmony_ci int err; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if (copy_from_user(&ctrl, argp, sizeof(ctrl))) 113162306a36Sopenharmony_ci return -EFAULT; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci down_read(&minfo->altout.lock); 113462306a36Sopenharmony_ci if (!minfo->outputs[1].output) { 113562306a36Sopenharmony_ci err = -ENXIO; 113662306a36Sopenharmony_ci } else if (minfo->outputs[1].output->getctrl) { 113762306a36Sopenharmony_ci err = minfo->outputs[1].output->getctrl(minfo->outputs[1].data, &ctrl); 113862306a36Sopenharmony_ci } else { 113962306a36Sopenharmony_ci err = -EINVAL; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci up_read(&minfo->altout.lock); 114262306a36Sopenharmony_ci if (err >= 0 && 114362306a36Sopenharmony_ci copy_to_user(argp, &ctrl, sizeof(ctrl))) 114462306a36Sopenharmony_ci return -EFAULT; 114562306a36Sopenharmony_ci return err; 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci case VIDIOC_S_CTRL: 114862306a36Sopenharmony_ci { 114962306a36Sopenharmony_ci struct v4l2_control ctrl; 115062306a36Sopenharmony_ci int err; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci if (copy_from_user(&ctrl, argp, sizeof(ctrl))) 115362306a36Sopenharmony_ci return -EFAULT; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci down_read(&minfo->altout.lock); 115662306a36Sopenharmony_ci if (!minfo->outputs[1].output) { 115762306a36Sopenharmony_ci err = -ENXIO; 115862306a36Sopenharmony_ci } else if (minfo->outputs[1].output->setctrl) { 115962306a36Sopenharmony_ci err = minfo->outputs[1].output->setctrl(minfo->outputs[1].data, &ctrl); 116062306a36Sopenharmony_ci } else { 116162306a36Sopenharmony_ci err = -EINVAL; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci up_read(&minfo->altout.lock); 116462306a36Sopenharmony_ci return err; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci return -ENOTTY; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic int matroxfb_blank(int blank, struct fb_info *info) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci int seq; 117562306a36Sopenharmony_ci int crtc; 117662306a36Sopenharmony_ci CRITFLAGS 117762306a36Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci DBG(__func__) 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (minfo->dead) 118262306a36Sopenharmony_ci return 1; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci switch (blank) { 118562306a36Sopenharmony_ci case FB_BLANK_NORMAL: seq = 0x20; crtc = 0x00; break; /* works ??? */ 118662306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: seq = 0x20; crtc = 0x10; break; 118762306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: seq = 0x20; crtc = 0x20; break; 118862306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: seq = 0x20; crtc = 0x30; break; 118962306a36Sopenharmony_ci default: seq = 0x00; crtc = 0x00; break; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci CRITBEGIN 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci mga_outb(M_SEQ_INDEX, 1); 119562306a36Sopenharmony_ci mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); 119662306a36Sopenharmony_ci mga_outb(M_EXTVGA_INDEX, 1); 119762306a36Sopenharmony_ci mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci CRITEND 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic const struct fb_ops matroxfb_ops = { 120462306a36Sopenharmony_ci .owner = THIS_MODULE, 120562306a36Sopenharmony_ci .fb_open = matroxfb_open, 120662306a36Sopenharmony_ci .fb_release = matroxfb_release, 120762306a36Sopenharmony_ci .fb_check_var = matroxfb_check_var, 120862306a36Sopenharmony_ci .fb_set_par = matroxfb_set_par, 120962306a36Sopenharmony_ci .fb_setcolreg = matroxfb_setcolreg, 121062306a36Sopenharmony_ci .fb_pan_display =matroxfb_pan_display, 121162306a36Sopenharmony_ci .fb_blank = matroxfb_blank, 121262306a36Sopenharmony_ci .fb_ioctl = matroxfb_ioctl, 121362306a36Sopenharmony_ci/* .fb_fillrect = <set by matrox_cfbX_init>, */ 121462306a36Sopenharmony_ci/* .fb_copyarea = <set by matrox_cfbX_init>, */ 121562306a36Sopenharmony_ci/* .fb_imageblit = <set by matrox_cfbX_init>, */ 121662306a36Sopenharmony_ci/* .fb_cursor = <set by matrox_cfbX_init>, */ 121762306a36Sopenharmony_ci}; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci#define RSDepth(X) (((X) >> 8) & 0x0F) 122062306a36Sopenharmony_ci#define RS8bpp 0x1 122162306a36Sopenharmony_ci#define RS15bpp 0x2 122262306a36Sopenharmony_ci#define RS16bpp 0x3 122362306a36Sopenharmony_ci#define RS32bpp 0x4 122462306a36Sopenharmony_ci#define RS4bpp 0x5 122562306a36Sopenharmony_ci#define RS24bpp 0x6 122662306a36Sopenharmony_ci#define RSText 0x7 122762306a36Sopenharmony_ci#define RSText8 0x8 122862306a36Sopenharmony_ci/* 9-F */ 122962306a36Sopenharmony_cistatic struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = { 123062306a36Sopenharmony_ci { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 }, 123162306a36Sopenharmony_ci { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 }, 123262306a36Sopenharmony_ci { { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 }, 123362306a36Sopenharmony_ci { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 }, 123462306a36Sopenharmony_ci { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 }, 123562306a36Sopenharmony_ci { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 }, 123662306a36Sopenharmony_ci { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */ 123762306a36Sopenharmony_ci { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */ 123862306a36Sopenharmony_ci}; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ 124162306a36Sopenharmony_cistatic unsigned int mem; /* "matroxfb:mem:xxxxxM" */ 124262306a36Sopenharmony_cistatic int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ 124362306a36Sopenharmony_cistatic int inv24; /* "matroxfb:inv24" */ 124462306a36Sopenharmony_cistatic int cross4MB = -1; /* "matroxfb:cross4MB" */ 124562306a36Sopenharmony_cistatic int disabled; /* "matroxfb:disabled" */ 124662306a36Sopenharmony_cistatic int noaccel; /* "matroxfb:noaccel" */ 124762306a36Sopenharmony_cistatic int nopan; /* "matroxfb:nopan" */ 124862306a36Sopenharmony_cistatic int no_pci_retry; /* "matroxfb:nopciretry" */ 124962306a36Sopenharmony_cistatic int novga; /* "matroxfb:novga" */ 125062306a36Sopenharmony_cistatic int nobios; /* "matroxfb:nobios" */ 125162306a36Sopenharmony_cistatic int noinit = 1; /* "matroxfb:init" */ 125262306a36Sopenharmony_cistatic int inverse; /* "matroxfb:inverse" */ 125362306a36Sopenharmony_cistatic int sgram; /* "matroxfb:sgram" */ 125462306a36Sopenharmony_cistatic int mtrr = 1; /* "matroxfb:nomtrr" */ 125562306a36Sopenharmony_cistatic int grayscale; /* "matroxfb:grayscale" */ 125662306a36Sopenharmony_cistatic int dev = -1; /* "matroxfb:dev:xxxxx" */ 125762306a36Sopenharmony_cistatic unsigned int vesa = ~0; /* "matroxfb:vesa:xxxxx" */ 125862306a36Sopenharmony_cistatic int depth = -1; /* "matroxfb:depth:xxxxx" */ 125962306a36Sopenharmony_cistatic unsigned int xres; /* "matroxfb:xres:xxxxx" */ 126062306a36Sopenharmony_cistatic unsigned int yres; /* "matroxfb:yres:xxxxx" */ 126162306a36Sopenharmony_cistatic unsigned int upper = ~0; /* "matroxfb:upper:xxxxx" */ 126262306a36Sopenharmony_cistatic unsigned int lower = ~0; /* "matroxfb:lower:xxxxx" */ 126362306a36Sopenharmony_cistatic unsigned int vslen; /* "matroxfb:vslen:xxxxx" */ 126462306a36Sopenharmony_cistatic unsigned int left = ~0; /* "matroxfb:left:xxxxx" */ 126562306a36Sopenharmony_cistatic unsigned int right = ~0; /* "matroxfb:right:xxxxx" */ 126662306a36Sopenharmony_cistatic unsigned int hslen; /* "matroxfb:hslen:xxxxx" */ 126762306a36Sopenharmony_cistatic unsigned int pixclock; /* "matroxfb:pixclock:xxxxx" */ 126862306a36Sopenharmony_cistatic int sync = -1; /* "matroxfb:sync:xxxxx" */ 126962306a36Sopenharmony_cistatic unsigned int fv; /* "matroxfb:fv:xxxxx" */ 127062306a36Sopenharmony_cistatic unsigned int fh; /* "matroxfb:fh:xxxxxk" */ 127162306a36Sopenharmony_cistatic unsigned int maxclk; /* "matroxfb:maxclk:xxxxM" */ 127262306a36Sopenharmony_cistatic int dfp; /* "matroxfb:dfp */ 127362306a36Sopenharmony_cistatic int dfp_type = -1; /* "matroxfb:dfp:xxx */ 127462306a36Sopenharmony_cistatic int memtype = -1; /* "matroxfb:memtype:xxx" */ 127562306a36Sopenharmony_cistatic char outputs[8]; /* "matroxfb:outputs:xxx" */ 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci#ifndef MODULE 127862306a36Sopenharmony_cistatic char videomode[64]; /* "matroxfb:mode:xxxxx" or "matroxfb:xxxxx" */ 127962306a36Sopenharmony_ci#endif 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cistatic int matroxfb_getmemory(struct matrox_fb_info *minfo, 128262306a36Sopenharmony_ci unsigned int maxSize, unsigned int *realSize) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci vaddr_t vm; 128562306a36Sopenharmony_ci unsigned int offs; 128662306a36Sopenharmony_ci unsigned int offs2; 128762306a36Sopenharmony_ci unsigned char orig; 128862306a36Sopenharmony_ci unsigned char bytes[32]; 128962306a36Sopenharmony_ci unsigned char* tmp; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci DBG(__func__) 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci vm = minfo->video.vbase; 129462306a36Sopenharmony_ci maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ 129562306a36Sopenharmony_ci /* at least 2MB */ 129662306a36Sopenharmony_ci if (maxSize < 0x0200000) return 0; 129762306a36Sopenharmony_ci if (maxSize > 0x2000000) maxSize = 0x2000000; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci mga_outb(M_EXTVGA_INDEX, 0x03); 130062306a36Sopenharmony_ci orig = mga_inb(M_EXTVGA_DATA); 130162306a36Sopenharmony_ci mga_outb(M_EXTVGA_DATA, orig | 0x80); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci tmp = bytes; 130462306a36Sopenharmony_ci for (offs = 0x100000; offs < maxSize; offs += 0x200000) 130562306a36Sopenharmony_ci *tmp++ = mga_readb(vm, offs); 130662306a36Sopenharmony_ci for (offs = 0x100000; offs < maxSize; offs += 0x200000) 130762306a36Sopenharmony_ci mga_writeb(vm, offs, 0x02); 130862306a36Sopenharmony_ci mga_outb(M_CACHEFLUSH, 0x00); 130962306a36Sopenharmony_ci for (offs = 0x100000; offs < maxSize; offs += 0x200000) { 131062306a36Sopenharmony_ci if (mga_readb(vm, offs) != 0x02) 131162306a36Sopenharmony_ci break; 131262306a36Sopenharmony_ci mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02); 131362306a36Sopenharmony_ci if (mga_readb(vm, offs)) 131462306a36Sopenharmony_ci break; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci tmp = bytes; 131762306a36Sopenharmony_ci for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000) 131862306a36Sopenharmony_ci mga_writeb(vm, offs2, *tmp++); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci mga_outb(M_EXTVGA_INDEX, 0x03); 132162306a36Sopenharmony_ci mga_outb(M_EXTVGA_DATA, orig); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci *realSize = offs - 0x100000; 132462306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM 132562306a36Sopenharmony_ci minfo->interleave = !(!isMillenium(minfo) || ((offs - 0x100000) & 0x3FFFFF)); 132662306a36Sopenharmony_ci#endif 132762306a36Sopenharmony_ci return 1; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistruct video_board { 133162306a36Sopenharmony_ci int maxvram; 133262306a36Sopenharmony_ci int maxdisplayable; 133362306a36Sopenharmony_ci int accelID; 133462306a36Sopenharmony_ci struct matrox_switch* lowlevel; 133562306a36Sopenharmony_ci }; 133662306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM 133762306a36Sopenharmony_cistatic struct video_board vbMillennium = { 133862306a36Sopenharmony_ci .maxvram = 0x0800000, 133962306a36Sopenharmony_ci .maxdisplayable = 0x0800000, 134062306a36Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGA2064W, 134162306a36Sopenharmony_ci .lowlevel = &matrox_millennium 134262306a36Sopenharmony_ci}; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic struct video_board vbMillennium2 = { 134562306a36Sopenharmony_ci .maxvram = 0x1000000, 134662306a36Sopenharmony_ci .maxdisplayable = 0x0800000, 134762306a36Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGA2164W, 134862306a36Sopenharmony_ci .lowlevel = &matrox_millennium 134962306a36Sopenharmony_ci}; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cistatic struct video_board vbMillennium2A = { 135262306a36Sopenharmony_ci .maxvram = 0x1000000, 135362306a36Sopenharmony_ci .maxdisplayable = 0x0800000, 135462306a36Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGA2164W_AGP, 135562306a36Sopenharmony_ci .lowlevel = &matrox_millennium 135662306a36Sopenharmony_ci}; 135762306a36Sopenharmony_ci#endif /* CONFIG_FB_MATROX_MILLENIUM */ 135862306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MYSTIQUE 135962306a36Sopenharmony_cistatic struct video_board vbMystique = { 136062306a36Sopenharmony_ci .maxvram = 0x0800000, 136162306a36Sopenharmony_ci .maxdisplayable = 0x0800000, 136262306a36Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGA1064SG, 136362306a36Sopenharmony_ci .lowlevel = &matrox_mystique 136462306a36Sopenharmony_ci}; 136562306a36Sopenharmony_ci#endif /* CONFIG_FB_MATROX_MYSTIQUE */ 136662306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_G 136762306a36Sopenharmony_cistatic struct video_board vbG100 = { 136862306a36Sopenharmony_ci .maxvram = 0x0800000, 136962306a36Sopenharmony_ci .maxdisplayable = 0x0800000, 137062306a36Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGAG100, 137162306a36Sopenharmony_ci .lowlevel = &matrox_G100 137262306a36Sopenharmony_ci}; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_cistatic struct video_board vbG200 = { 137562306a36Sopenharmony_ci .maxvram = 0x1000000, 137662306a36Sopenharmony_ci .maxdisplayable = 0x1000000, 137762306a36Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGAG200, 137862306a36Sopenharmony_ci .lowlevel = &matrox_G100 137962306a36Sopenharmony_ci}; 138062306a36Sopenharmony_cistatic struct video_board vbG200eW = { 138162306a36Sopenharmony_ci .maxvram = 0x1000000, 138262306a36Sopenharmony_ci .maxdisplayable = 0x0800000, 138362306a36Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGAG200, 138462306a36Sopenharmony_ci .lowlevel = &matrox_G100 138562306a36Sopenharmony_ci}; 138662306a36Sopenharmony_ci/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for 138762306a36Sopenharmony_ci whole 32MB */ 138862306a36Sopenharmony_cistatic struct video_board vbG400 = { 138962306a36Sopenharmony_ci .maxvram = 0x2000000, 139062306a36Sopenharmony_ci .maxdisplayable = 0x1000000, 139162306a36Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGAG400, 139262306a36Sopenharmony_ci .lowlevel = &matrox_G100 139362306a36Sopenharmony_ci}; 139462306a36Sopenharmony_ci#endif 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci#define DEVF_VIDEO64BIT 0x0001 139762306a36Sopenharmony_ci#define DEVF_SWAPS 0x0002 139862306a36Sopenharmony_ci#define DEVF_SRCORG 0x0004 139962306a36Sopenharmony_ci#define DEVF_DUALHEAD 0x0008 140062306a36Sopenharmony_ci#define DEVF_CROSS4MB 0x0010 140162306a36Sopenharmony_ci#define DEVF_TEXT4B 0x0020 140262306a36Sopenharmony_ci/* #define DEVF_recycled 0x0040 */ 140362306a36Sopenharmony_ci/* #define DEVF_recycled 0x0080 */ 140462306a36Sopenharmony_ci#define DEVF_SUPPORT32MB 0x0100 140562306a36Sopenharmony_ci#define DEVF_ANY_VXRES 0x0200 140662306a36Sopenharmony_ci#define DEVF_TEXT16B 0x0400 140762306a36Sopenharmony_ci#define DEVF_CRTC2 0x0800 140862306a36Sopenharmony_ci#define DEVF_MAVEN_CAPABLE 0x1000 140962306a36Sopenharmony_ci#define DEVF_PANELLINK_CAPABLE 0x2000 141062306a36Sopenharmony_ci#define DEVF_G450DAC 0x4000 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB) 141362306a36Sopenharmony_ci#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD) 141462306a36Sopenharmony_ci#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */ 141562306a36Sopenharmony_ci#define DEVF_G200 (DEVF_G2CORE) 141662306a36Sopenharmony_ci#define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2) 141762306a36Sopenharmony_ci/* if you'll find how to drive DFP... */ 141862306a36Sopenharmony_ci#define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD) 141962306a36Sopenharmony_ci#define DEVF_G550 (DEVF_G450) 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_cistatic struct board { 142262306a36Sopenharmony_ci unsigned short vendor, device, rev, svid, sid; 142362306a36Sopenharmony_ci unsigned int flags; 142462306a36Sopenharmony_ci unsigned int maxclk; 142562306a36Sopenharmony_ci enum mga_chip chip; 142662306a36Sopenharmony_ci struct video_board* base; 142762306a36Sopenharmony_ci const char* name; 142862306a36Sopenharmony_ci } dev_list[] = { 142962306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM 143062306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF, 143162306a36Sopenharmony_ci 0, 0, 143262306a36Sopenharmony_ci DEVF_TEXT4B, 143362306a36Sopenharmony_ci 230000, 143462306a36Sopenharmony_ci MGA_2064, 143562306a36Sopenharmony_ci &vbMillennium, 143662306a36Sopenharmony_ci "Millennium (PCI)"}, 143762306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF, 143862306a36Sopenharmony_ci 0, 0, 143962306a36Sopenharmony_ci DEVF_SWAPS, 144062306a36Sopenharmony_ci 220000, 144162306a36Sopenharmony_ci MGA_2164, 144262306a36Sopenharmony_ci &vbMillennium2, 144362306a36Sopenharmony_ci "Millennium II (PCI)"}, 144462306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF, 144562306a36Sopenharmony_ci 0, 0, 144662306a36Sopenharmony_ci DEVF_SWAPS, 144762306a36Sopenharmony_ci 250000, 144862306a36Sopenharmony_ci MGA_2164, 144962306a36Sopenharmony_ci &vbMillennium2A, 145062306a36Sopenharmony_ci "Millennium II (AGP)"}, 145162306a36Sopenharmony_ci#endif 145262306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MYSTIQUE 145362306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02, 145462306a36Sopenharmony_ci 0, 0, 145562306a36Sopenharmony_ci DEVF_VIDEO64BIT | DEVF_CROSS4MB, 145662306a36Sopenharmony_ci 180000, 145762306a36Sopenharmony_ci MGA_1064, 145862306a36Sopenharmony_ci &vbMystique, 145962306a36Sopenharmony_ci "Mystique (PCI)"}, 146062306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF, 146162306a36Sopenharmony_ci 0, 0, 146262306a36Sopenharmony_ci DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, 146362306a36Sopenharmony_ci 220000, 146462306a36Sopenharmony_ci MGA_1164, 146562306a36Sopenharmony_ci &vbMystique, 146662306a36Sopenharmony_ci "Mystique 220 (PCI)"}, 146762306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS_AGP, 0x02, 146862306a36Sopenharmony_ci 0, 0, 146962306a36Sopenharmony_ci DEVF_VIDEO64BIT | DEVF_CROSS4MB, 147062306a36Sopenharmony_ci 180000, 147162306a36Sopenharmony_ci MGA_1064, 147262306a36Sopenharmony_ci &vbMystique, 147362306a36Sopenharmony_ci "Mystique (AGP)"}, 147462306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS_AGP, 0xFF, 147562306a36Sopenharmony_ci 0, 0, 147662306a36Sopenharmony_ci DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, 147762306a36Sopenharmony_ci 220000, 147862306a36Sopenharmony_ci MGA_1164, 147962306a36Sopenharmony_ci &vbMystique, 148062306a36Sopenharmony_ci "Mystique 220 (AGP)"}, 148162306a36Sopenharmony_ci#endif 148262306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_G 148362306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, 148462306a36Sopenharmony_ci 0, 0, 148562306a36Sopenharmony_ci DEVF_G100, 148662306a36Sopenharmony_ci 230000, 148762306a36Sopenharmony_ci MGA_G100, 148862306a36Sopenharmony_ci &vbG100, 148962306a36Sopenharmony_ci "MGA-G100 (PCI)"}, 149062306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, 149162306a36Sopenharmony_ci 0, 0, 149262306a36Sopenharmony_ci DEVF_G100, 149362306a36Sopenharmony_ci 230000, 149462306a36Sopenharmony_ci MGA_G100, 149562306a36Sopenharmony_ci &vbG100, 149662306a36Sopenharmony_ci "MGA-G100 (AGP)"}, 149762306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF, 149862306a36Sopenharmony_ci 0, 0, 149962306a36Sopenharmony_ci DEVF_G200, 150062306a36Sopenharmony_ci 250000, 150162306a36Sopenharmony_ci MGA_G200, 150262306a36Sopenharmony_ci &vbG200, 150362306a36Sopenharmony_ci "MGA-G200 (PCI)"}, 150462306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, 0x0532, 0xFF, 150562306a36Sopenharmony_ci 0, 0, 150662306a36Sopenharmony_ci DEVF_G200, 150762306a36Sopenharmony_ci 250000, 150862306a36Sopenharmony_ci MGA_G200, 150962306a36Sopenharmony_ci &vbG200eW, 151062306a36Sopenharmony_ci "MGA-G200eW (PCI)"}, 151162306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 151262306a36Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, 151362306a36Sopenharmony_ci DEVF_G200, 151462306a36Sopenharmony_ci 220000, 151562306a36Sopenharmony_ci MGA_G200, 151662306a36Sopenharmony_ci &vbG200, 151762306a36Sopenharmony_ci "MGA-G200 (AGP)"}, 151862306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 151962306a36Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP, 152062306a36Sopenharmony_ci DEVF_G200, 152162306a36Sopenharmony_ci 230000, 152262306a36Sopenharmony_ci MGA_G200, 152362306a36Sopenharmony_ci &vbG200, 152462306a36Sopenharmony_ci "Mystique G200 (AGP)"}, 152562306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 152662306a36Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP, 152762306a36Sopenharmony_ci DEVF_G200, 152862306a36Sopenharmony_ci 250000, 152962306a36Sopenharmony_ci MGA_G200, 153062306a36Sopenharmony_ci &vbG200, 153162306a36Sopenharmony_ci "Millennium G200 (AGP)"}, 153262306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 153362306a36Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP, 153462306a36Sopenharmony_ci DEVF_G200, 153562306a36Sopenharmony_ci 230000, 153662306a36Sopenharmony_ci MGA_G200, 153762306a36Sopenharmony_ci &vbG200, 153862306a36Sopenharmony_ci "Marvel G200 (AGP)"}, 153962306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 154062306a36Sopenharmony_ci PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP, 154162306a36Sopenharmony_ci DEVF_G200, 154262306a36Sopenharmony_ci 230000, 154362306a36Sopenharmony_ci MGA_G200, 154462306a36Sopenharmony_ci &vbG200, 154562306a36Sopenharmony_ci "MGA-G200 (AGP)"}, 154662306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 154762306a36Sopenharmony_ci 0, 0, 154862306a36Sopenharmony_ci DEVF_G200, 154962306a36Sopenharmony_ci 230000, 155062306a36Sopenharmony_ci MGA_G200, 155162306a36Sopenharmony_ci &vbG200, 155262306a36Sopenharmony_ci "G200 (AGP)"}, 155362306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, 155462306a36Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP, 155562306a36Sopenharmony_ci DEVF_G400, 155662306a36Sopenharmony_ci 360000, 155762306a36Sopenharmony_ci MGA_G400, 155862306a36Sopenharmony_ci &vbG400, 155962306a36Sopenharmony_ci "Millennium G400 MAX (AGP)"}, 156062306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, 156162306a36Sopenharmony_ci 0, 0, 156262306a36Sopenharmony_ci DEVF_G400, 156362306a36Sopenharmony_ci 300000, 156462306a36Sopenharmony_ci MGA_G400, 156562306a36Sopenharmony_ci &vbG400, 156662306a36Sopenharmony_ci "G400 (AGP)"}, 156762306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0xFF, 156862306a36Sopenharmony_ci 0, 0, 156962306a36Sopenharmony_ci DEVF_G450, 157062306a36Sopenharmony_ci 360000, 157162306a36Sopenharmony_ci MGA_G450, 157262306a36Sopenharmony_ci &vbG400, 157362306a36Sopenharmony_ci "G450"}, 157462306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, 0xFF, 157562306a36Sopenharmony_ci 0, 0, 157662306a36Sopenharmony_ci DEVF_G550, 157762306a36Sopenharmony_ci 360000, 157862306a36Sopenharmony_ci MGA_G550, 157962306a36Sopenharmony_ci &vbG400, 158062306a36Sopenharmony_ci "G550"}, 158162306a36Sopenharmony_ci#endif 158262306a36Sopenharmony_ci {0, 0, 0xFF, 158362306a36Sopenharmony_ci 0, 0, 158462306a36Sopenharmony_ci 0, 158562306a36Sopenharmony_ci 0, 158662306a36Sopenharmony_ci 0, 158762306a36Sopenharmony_ci NULL, 158862306a36Sopenharmony_ci NULL}}; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci#ifndef MODULE 159162306a36Sopenharmony_cistatic const struct fb_videomode defaultmode = { 159262306a36Sopenharmony_ci /* 640x480 @ 60Hz, 31.5 kHz */ 159362306a36Sopenharmony_ci NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, 159462306a36Sopenharmony_ci 0, FB_VMODE_NONINTERLACED 159562306a36Sopenharmony_ci}; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_cistatic int hotplug = 0; 159862306a36Sopenharmony_ci#endif /* !MODULE */ 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic void setDefaultOutputs(struct matrox_fb_info *minfo) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci unsigned int i; 160362306a36Sopenharmony_ci const char* ptr; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci minfo->outputs[0].default_src = MATROXFB_SRC_CRTC1; 160662306a36Sopenharmony_ci if (minfo->devflags.g450dac) { 160762306a36Sopenharmony_ci minfo->outputs[1].default_src = MATROXFB_SRC_CRTC1; 160862306a36Sopenharmony_ci minfo->outputs[2].default_src = MATROXFB_SRC_CRTC1; 160962306a36Sopenharmony_ci } else if (dfp) { 161062306a36Sopenharmony_ci minfo->outputs[2].default_src = MATROXFB_SRC_CRTC1; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci ptr = outputs; 161362306a36Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 161462306a36Sopenharmony_ci char c = *ptr++; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci if (c == 0) { 161762306a36Sopenharmony_ci break; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci if (c == '0') { 162062306a36Sopenharmony_ci minfo->outputs[i].default_src = MATROXFB_SRC_NONE; 162162306a36Sopenharmony_ci } else if (c == '1') { 162262306a36Sopenharmony_ci minfo->outputs[i].default_src = MATROXFB_SRC_CRTC1; 162362306a36Sopenharmony_ci } else if (c == '2' && minfo->devflags.crtc2) { 162462306a36Sopenharmony_ci minfo->outputs[i].default_src = MATROXFB_SRC_CRTC2; 162562306a36Sopenharmony_ci } else { 162662306a36Sopenharmony_ci printk(KERN_ERR "matroxfb: Unknown outputs setting\n"); 162762306a36Sopenharmony_ci break; 162862306a36Sopenharmony_ci } 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci /* Nullify this option for subsequent adapters */ 163162306a36Sopenharmony_ci outputs[0] = 0; 163262306a36Sopenharmony_ci} 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_cistatic int initMatrox2(struct matrox_fb_info *minfo, struct board *b) 163562306a36Sopenharmony_ci{ 163662306a36Sopenharmony_ci unsigned long ctrlptr_phys = 0; 163762306a36Sopenharmony_ci unsigned long video_base_phys = 0; 163862306a36Sopenharmony_ci unsigned int memsize; 163962306a36Sopenharmony_ci int err; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci static const struct pci_device_id intel_82437[] = { 164262306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) }, 164362306a36Sopenharmony_ci { }, 164462306a36Sopenharmony_ci }; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci DBG(__func__) 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci /* set default values... */ 164962306a36Sopenharmony_ci vesafb_defined.accel_flags = FB_ACCELF_TEXT; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci minfo->hw_switch = b->base->lowlevel; 165262306a36Sopenharmony_ci minfo->devflags.accelerator = b->base->accelID; 165362306a36Sopenharmony_ci minfo->max_pixel_clock = b->maxclk; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name); 165662306a36Sopenharmony_ci minfo->capable.plnwt = 1; 165762306a36Sopenharmony_ci minfo->chip = b->chip; 165862306a36Sopenharmony_ci minfo->capable.srcorg = b->flags & DEVF_SRCORG; 165962306a36Sopenharmony_ci minfo->devflags.video64bits = b->flags & DEVF_VIDEO64BIT; 166062306a36Sopenharmony_ci if (b->flags & DEVF_TEXT4B) { 166162306a36Sopenharmony_ci minfo->devflags.vgastep = 4; 166262306a36Sopenharmony_ci minfo->devflags.textmode = 4; 166362306a36Sopenharmony_ci minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP16; 166462306a36Sopenharmony_ci } else if (b->flags & DEVF_TEXT16B) { 166562306a36Sopenharmony_ci minfo->devflags.vgastep = 16; 166662306a36Sopenharmony_ci minfo->devflags.textmode = 1; 166762306a36Sopenharmony_ci minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP16; 166862306a36Sopenharmony_ci } else { 166962306a36Sopenharmony_ci minfo->devflags.vgastep = 8; 167062306a36Sopenharmony_ci minfo->devflags.textmode = 1; 167162306a36Sopenharmony_ci minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP8; 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci minfo->devflags.support32MB = (b->flags & DEVF_SUPPORT32MB) != 0; 167462306a36Sopenharmony_ci minfo->devflags.precise_width = !(b->flags & DEVF_ANY_VXRES); 167562306a36Sopenharmony_ci minfo->devflags.crtc2 = (b->flags & DEVF_CRTC2) != 0; 167662306a36Sopenharmony_ci minfo->devflags.maven_capable = (b->flags & DEVF_MAVEN_CAPABLE) != 0; 167762306a36Sopenharmony_ci minfo->devflags.dualhead = (b->flags & DEVF_DUALHEAD) != 0; 167862306a36Sopenharmony_ci minfo->devflags.dfp_type = dfp_type; 167962306a36Sopenharmony_ci minfo->devflags.g450dac = (b->flags & DEVF_G450DAC) != 0; 168062306a36Sopenharmony_ci minfo->devflags.textstep = minfo->devflags.vgastep * minfo->devflags.textmode; 168162306a36Sopenharmony_ci minfo->devflags.textvram = 65536 / minfo->devflags.textmode; 168262306a36Sopenharmony_ci setDefaultOutputs(minfo); 168362306a36Sopenharmony_ci if (b->flags & DEVF_PANELLINK_CAPABLE) { 168462306a36Sopenharmony_ci minfo->outputs[2].data = minfo; 168562306a36Sopenharmony_ci minfo->outputs[2].output = &panellink_output; 168662306a36Sopenharmony_ci minfo->outputs[2].src = minfo->outputs[2].default_src; 168762306a36Sopenharmony_ci minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR; 168862306a36Sopenharmony_ci minfo->devflags.panellink = 1; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci if (minfo->capable.cross4MB < 0) 169262306a36Sopenharmony_ci minfo->capable.cross4MB = b->flags & DEVF_CROSS4MB; 169362306a36Sopenharmony_ci if (b->flags & DEVF_SWAPS) { 169462306a36Sopenharmony_ci ctrlptr_phys = pci_resource_start(minfo->pcidev, 1); 169562306a36Sopenharmony_ci video_base_phys = pci_resource_start(minfo->pcidev, 0); 169662306a36Sopenharmony_ci minfo->devflags.fbResource = PCI_BASE_ADDRESS_0; 169762306a36Sopenharmony_ci } else { 169862306a36Sopenharmony_ci ctrlptr_phys = pci_resource_start(minfo->pcidev, 0); 169962306a36Sopenharmony_ci video_base_phys = pci_resource_start(minfo->pcidev, 1); 170062306a36Sopenharmony_ci minfo->devflags.fbResource = PCI_BASE_ADDRESS_1; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci err = -EINVAL; 170362306a36Sopenharmony_ci if (!ctrlptr_phys) { 170462306a36Sopenharmony_ci printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n"); 170562306a36Sopenharmony_ci goto fail; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci if (!video_base_phys) { 170862306a36Sopenharmony_ci printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n"); 170962306a36Sopenharmony_ci goto fail; 171062306a36Sopenharmony_ci } 171162306a36Sopenharmony_ci memsize = b->base->maxvram; 171262306a36Sopenharmony_ci if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) { 171362306a36Sopenharmony_ci goto fail; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) { 171662306a36Sopenharmony_ci goto failCtrlMR; 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci minfo->video.len_maximum = memsize; 171962306a36Sopenharmony_ci /* convert mem (autodetect k, M) */ 172062306a36Sopenharmony_ci if (mem < 1024) mem *= 1024; 172162306a36Sopenharmony_ci if (mem < 0x00100000) mem *= 1024; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci if (mem && (mem < memsize)) 172462306a36Sopenharmony_ci memsize = mem; 172562306a36Sopenharmony_ci err = -ENOMEM; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci minfo->mmio.vbase.vaddr = ioremap(ctrlptr_phys, 16384); 172862306a36Sopenharmony_ci if (!minfo->mmio.vbase.vaddr) { 172962306a36Sopenharmony_ci printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys); 173062306a36Sopenharmony_ci goto failVideoMR; 173162306a36Sopenharmony_ci } 173262306a36Sopenharmony_ci minfo->mmio.base = ctrlptr_phys; 173362306a36Sopenharmony_ci minfo->mmio.len = 16384; 173462306a36Sopenharmony_ci minfo->video.base = video_base_phys; 173562306a36Sopenharmony_ci minfo->video.vbase.vaddr = ioremap_wc(video_base_phys, memsize); 173662306a36Sopenharmony_ci if (!minfo->video.vbase.vaddr) { 173762306a36Sopenharmony_ci printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", 173862306a36Sopenharmony_ci video_base_phys, memsize); 173962306a36Sopenharmony_ci goto failCtrlIO; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci { 174262306a36Sopenharmony_ci u_int32_t cmd; 174362306a36Sopenharmony_ci u_int32_t mga_option; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci pci_read_config_dword(minfo->pcidev, PCI_OPTION_REG, &mga_option); 174662306a36Sopenharmony_ci pci_read_config_dword(minfo->pcidev, PCI_COMMAND, &cmd); 174762306a36Sopenharmony_ci mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */ 174862306a36Sopenharmony_ci mga_option |= MX_OPTION_BSWAP; 174962306a36Sopenharmony_ci /* disable palette snooping */ 175062306a36Sopenharmony_ci cmd &= ~PCI_COMMAND_VGA_PALETTE; 175162306a36Sopenharmony_ci if (pci_dev_present(intel_82437)) { 175262306a36Sopenharmony_ci if (!(mga_option & 0x20000000) && !minfo->devflags.nopciretry) { 175362306a36Sopenharmony_ci printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n"); 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci mga_option |= 0x20000000; 175662306a36Sopenharmony_ci minfo->devflags.nopciretry = 1; 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci pci_write_config_dword(minfo->pcidev, PCI_COMMAND, cmd); 175962306a36Sopenharmony_ci pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mga_option); 176062306a36Sopenharmony_ci minfo->hw.MXoptionReg = mga_option; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */ 176362306a36Sopenharmony_ci /* maybe preinit() candidate, but it is same... for all devices... at this time... */ 176462306a36Sopenharmony_ci pci_write_config_dword(minfo->pcidev, PCI_MGA_INDEX, 0x00003C00); 176562306a36Sopenharmony_ci } 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci err = -ENXIO; 176862306a36Sopenharmony_ci matroxfb_read_pins(minfo); 176962306a36Sopenharmony_ci if (minfo->hw_switch->preinit(minfo)) { 177062306a36Sopenharmony_ci goto failVideoIO; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci err = -ENOMEM; 177462306a36Sopenharmony_ci if (!matroxfb_getmemory(minfo, memsize, &minfo->video.len) || !minfo->video.len) { 177562306a36Sopenharmony_ci printk(KERN_ERR "matroxfb: cannot determine memory size\n"); 177662306a36Sopenharmony_ci goto failVideoIO; 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci minfo->devflags.ydstorg = 0; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci minfo->video.base = video_base_phys; 178162306a36Sopenharmony_ci minfo->video.len_usable = minfo->video.len; 178262306a36Sopenharmony_ci if (minfo->video.len_usable > b->base->maxdisplayable) 178362306a36Sopenharmony_ci minfo->video.len_usable = b->base->maxdisplayable; 178462306a36Sopenharmony_ci if (mtrr) 178562306a36Sopenharmony_ci minfo->wc_cookie = arch_phys_wc_add(video_base_phys, 178662306a36Sopenharmony_ci minfo->video.len); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci if (!minfo->devflags.novga) 178962306a36Sopenharmony_ci request_region(0x3C0, 32, "matrox"); 179062306a36Sopenharmony_ci matroxfb_g450_connect(minfo); 179162306a36Sopenharmony_ci minfo->hw_switch->reset(minfo); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci minfo->fbcon.monspecs.hfmin = 0; 179462306a36Sopenharmony_ci minfo->fbcon.monspecs.hfmax = fh; 179562306a36Sopenharmony_ci minfo->fbcon.monspecs.vfmin = 0; 179662306a36Sopenharmony_ci minfo->fbcon.monspecs.vfmax = fv; 179762306a36Sopenharmony_ci minfo->fbcon.monspecs.dpms = 0; /* TBD */ 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci /* static settings */ 180062306a36Sopenharmony_ci vesafb_defined.red = colors[depth-1].red; 180162306a36Sopenharmony_ci vesafb_defined.green = colors[depth-1].green; 180262306a36Sopenharmony_ci vesafb_defined.blue = colors[depth-1].blue; 180362306a36Sopenharmony_ci vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel; 180462306a36Sopenharmony_ci vesafb_defined.grayscale = grayscale; 180562306a36Sopenharmony_ci vesafb_defined.vmode = 0; 180662306a36Sopenharmony_ci if (noaccel) 180762306a36Sopenharmony_ci vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci minfo->fbops = matroxfb_ops; 181062306a36Sopenharmony_ci minfo->fbcon.fbops = &minfo->fbops; 181162306a36Sopenharmony_ci minfo->fbcon.pseudo_palette = minfo->cmap; 181262306a36Sopenharmony_ci minfo->fbcon.flags = FBINFO_PARTIAL_PAN_OK | /* Prefer panning for scroll under MC viewer/edit */ 181362306a36Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | /* We have hw-assisted bmove */ 181462306a36Sopenharmony_ci FBINFO_HWACCEL_FILLRECT | /* And fillrect */ 181562306a36Sopenharmony_ci FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */ 181662306a36Sopenharmony_ci FBINFO_HWACCEL_XPAN | /* And we support both horizontal */ 181762306a36Sopenharmony_ci FBINFO_HWACCEL_YPAN | /* And vertical panning */ 181862306a36Sopenharmony_ci FBINFO_READS_FAST; 181962306a36Sopenharmony_ci minfo->video.len_usable &= PAGE_MASK; 182062306a36Sopenharmony_ci fb_alloc_cmap(&minfo->fbcon.cmap, 256, 1); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci#ifndef MODULE 182362306a36Sopenharmony_ci /* mode database is marked __init!!! */ 182462306a36Sopenharmony_ci if (!hotplug) { 182562306a36Sopenharmony_ci fb_find_mode(&vesafb_defined, &minfo->fbcon, videomode[0] ? videomode : NULL, 182662306a36Sopenharmony_ci NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel); 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci#endif /* !MODULE */ 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* mode modifiers */ 183162306a36Sopenharmony_ci if (hslen) 183262306a36Sopenharmony_ci vesafb_defined.hsync_len = hslen; 183362306a36Sopenharmony_ci if (vslen) 183462306a36Sopenharmony_ci vesafb_defined.vsync_len = vslen; 183562306a36Sopenharmony_ci if (left != ~0) 183662306a36Sopenharmony_ci vesafb_defined.left_margin = left; 183762306a36Sopenharmony_ci if (right != ~0) 183862306a36Sopenharmony_ci vesafb_defined.right_margin = right; 183962306a36Sopenharmony_ci if (upper != ~0) 184062306a36Sopenharmony_ci vesafb_defined.upper_margin = upper; 184162306a36Sopenharmony_ci if (lower != ~0) 184262306a36Sopenharmony_ci vesafb_defined.lower_margin = lower; 184362306a36Sopenharmony_ci if (xres) 184462306a36Sopenharmony_ci vesafb_defined.xres = xres; 184562306a36Sopenharmony_ci if (yres) 184662306a36Sopenharmony_ci vesafb_defined.yres = yres; 184762306a36Sopenharmony_ci if (sync != -1) 184862306a36Sopenharmony_ci vesafb_defined.sync = sync; 184962306a36Sopenharmony_ci else if (vesafb_defined.sync == ~0) { 185062306a36Sopenharmony_ci vesafb_defined.sync = 0; 185162306a36Sopenharmony_ci if (yres < 400) 185262306a36Sopenharmony_ci vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT; 185362306a36Sopenharmony_ci else if (yres < 480) 185462306a36Sopenharmony_ci vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT; 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci /* fv, fh, maxclk limits was specified */ 185862306a36Sopenharmony_ci { 185962306a36Sopenharmony_ci unsigned int tmp; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci if (fv) { 186262306a36Sopenharmony_ci tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres 186362306a36Sopenharmony_ci + vesafb_defined.lower_margin + vesafb_defined.vsync_len); 186462306a36Sopenharmony_ci if ((tmp < fh) || (fh == 0)) fh = tmp; 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci if (fh) { 186762306a36Sopenharmony_ci tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres 186862306a36Sopenharmony_ci + vesafb_defined.right_margin + vesafb_defined.hsync_len); 186962306a36Sopenharmony_ci if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp; 187062306a36Sopenharmony_ci } 187162306a36Sopenharmony_ci tmp = (maxclk + 499) / 500; 187262306a36Sopenharmony_ci if (tmp) { 187362306a36Sopenharmony_ci tmp = (2000000000 + tmp) / tmp; 187462306a36Sopenharmony_ci if (tmp > pixclock) pixclock = tmp; 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci if (pixclock) { 187862306a36Sopenharmony_ci if (pixclock < 2000) /* > 500MHz */ 187962306a36Sopenharmony_ci pixclock = 4000; /* 250MHz */ 188062306a36Sopenharmony_ci if (pixclock > 1000000) 188162306a36Sopenharmony_ci pixclock = 1000000; /* 1MHz */ 188262306a36Sopenharmony_ci vesafb_defined.pixclock = pixclock; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci /* FIXME: Where to move this?! */ 188662306a36Sopenharmony_ci#if defined(CONFIG_PPC_PMAC) 188762306a36Sopenharmony_ci#ifndef MODULE 188862306a36Sopenharmony_ci if (machine_is(powermac)) { 188962306a36Sopenharmony_ci struct fb_var_screeninfo var; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci if (default_vmode <= 0 || default_vmode > VMODE_MAX) 189262306a36Sopenharmony_ci default_vmode = VMODE_640_480_60; 189362306a36Sopenharmony_ci#if defined(CONFIG_PPC32) 189462306a36Sopenharmony_ci if (IS_REACHABLE(CONFIG_NVRAM) && default_cmode == CMODE_NVRAM) 189562306a36Sopenharmony_ci default_cmode = nvram_read_byte(NV_CMODE); 189662306a36Sopenharmony_ci#endif 189762306a36Sopenharmony_ci if (default_cmode < CMODE_8 || default_cmode > CMODE_32) 189862306a36Sopenharmony_ci default_cmode = CMODE_8; 189962306a36Sopenharmony_ci if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) { 190062306a36Sopenharmony_ci var.accel_flags = vesafb_defined.accel_flags; 190162306a36Sopenharmony_ci var.xoffset = var.yoffset = 0; 190262306a36Sopenharmony_ci /* Note: mac_vmode_to_var() does not set all parameters */ 190362306a36Sopenharmony_ci vesafb_defined = var; 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci#endif /* !MODULE */ 190762306a36Sopenharmony_ci#endif /* CONFIG_PPC_PMAC */ 190862306a36Sopenharmony_ci vesafb_defined.xres_virtual = vesafb_defined.xres; 190962306a36Sopenharmony_ci if (nopan) { 191062306a36Sopenharmony_ci vesafb_defined.yres_virtual = vesafb_defined.yres; 191162306a36Sopenharmony_ci } else { 191262306a36Sopenharmony_ci vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough 191362306a36Sopenharmony_ci to yres_virtual * xres_virtual < 2^32 */ 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci matroxfb_init_fix(minfo); 191662306a36Sopenharmony_ci minfo->fbcon.screen_base = vaddr_va(minfo->video.vbase); 191762306a36Sopenharmony_ci /* Normalize values (namely yres_virtual) */ 191862306a36Sopenharmony_ci matroxfb_check_var(&vesafb_defined, &minfo->fbcon); 191962306a36Sopenharmony_ci /* And put it into "current" var. Do NOT program hardware yet, or we'll not take over 192062306a36Sopenharmony_ci * vgacon correctly. fbcon_startup will call fb_set_par for us, WITHOUT check_var, 192162306a36Sopenharmony_ci * and unfortunately it will do it BEFORE vgacon contents is saved, so it won't work 192262306a36Sopenharmony_ci * anyway. But we at least tried... */ 192362306a36Sopenharmony_ci minfo->fbcon.var = vesafb_defined; 192462306a36Sopenharmony_ci err = -EINVAL; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n", 192762306a36Sopenharmony_ci vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, 192862306a36Sopenharmony_ci vesafb_defined.xres_virtual, vesafb_defined.yres_virtual); 192962306a36Sopenharmony_ci printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n", 193062306a36Sopenharmony_ci minfo->video.base, vaddr_va(minfo->video.vbase), minfo->video.len); 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci/* We do not have to set currcon to 0... register_framebuffer do it for us on first console 193362306a36Sopenharmony_ci * and we do not want currcon == 0 for subsequent framebuffers */ 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci minfo->fbcon.device = &minfo->pcidev->dev; 193662306a36Sopenharmony_ci if (register_framebuffer(&minfo->fbcon) < 0) { 193762306a36Sopenharmony_ci goto failVideoIO; 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci fb_info(&minfo->fbcon, "%s frame buffer device\n", minfo->fbcon.fix.id); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci /* there is no console on this fb... but we have to initialize hardware 194262306a36Sopenharmony_ci * until someone tells me what is proper thing to do */ 194362306a36Sopenharmony_ci if (!minfo->initialized) { 194462306a36Sopenharmony_ci fb_info(&minfo->fbcon, "initializing hardware\n"); 194562306a36Sopenharmony_ci /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var 194662306a36Sopenharmony_ci * already before, so register_framebuffer works correctly. */ 194762306a36Sopenharmony_ci vesafb_defined.activate |= FB_ACTIVATE_FORCE; 194862306a36Sopenharmony_ci fb_set_var(&minfo->fbcon, &vesafb_defined); 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci return 0; 195262306a36Sopenharmony_cifailVideoIO:; 195362306a36Sopenharmony_ci matroxfb_g450_shutdown(minfo); 195462306a36Sopenharmony_ci iounmap(minfo->video.vbase.vaddr); 195562306a36Sopenharmony_cifailCtrlIO:; 195662306a36Sopenharmony_ci iounmap(minfo->mmio.vbase.vaddr); 195762306a36Sopenharmony_cifailVideoMR:; 195862306a36Sopenharmony_ci release_mem_region(video_base_phys, minfo->video.len_maximum); 195962306a36Sopenharmony_cifailCtrlMR:; 196062306a36Sopenharmony_ci release_mem_region(ctrlptr_phys, 16384); 196162306a36Sopenharmony_cifail:; 196262306a36Sopenharmony_ci return err; 196362306a36Sopenharmony_ci} 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_cistatic LIST_HEAD(matroxfb_list); 196662306a36Sopenharmony_cistatic LIST_HEAD(matroxfb_driver_list); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci#define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb) 196962306a36Sopenharmony_ci#define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node) 197062306a36Sopenharmony_ciint matroxfb_register_driver(struct matroxfb_driver* drv) { 197162306a36Sopenharmony_ci struct matrox_fb_info* minfo; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci list_add(&drv->node, &matroxfb_driver_list); 197462306a36Sopenharmony_ci list_for_each_entry(minfo, &matroxfb_list, next_fb) { 197562306a36Sopenharmony_ci void* p; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci if (minfo->drivers_count == MATROXFB_MAX_FB_DRIVERS) 197862306a36Sopenharmony_ci continue; 197962306a36Sopenharmony_ci p = drv->probe(minfo); 198062306a36Sopenharmony_ci if (p) { 198162306a36Sopenharmony_ci minfo->drivers_data[minfo->drivers_count] = p; 198262306a36Sopenharmony_ci minfo->drivers[minfo->drivers_count++] = drv; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci return 0; 198662306a36Sopenharmony_ci} 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_civoid matroxfb_unregister_driver(struct matroxfb_driver* drv) { 198962306a36Sopenharmony_ci struct matrox_fb_info* minfo; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci list_del(&drv->node); 199262306a36Sopenharmony_ci list_for_each_entry(minfo, &matroxfb_list, next_fb) { 199362306a36Sopenharmony_ci int i; 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci for (i = 0; i < minfo->drivers_count; ) { 199662306a36Sopenharmony_ci if (minfo->drivers[i] == drv) { 199762306a36Sopenharmony_ci if (drv && drv->remove) 199862306a36Sopenharmony_ci drv->remove(minfo, minfo->drivers_data[i]); 199962306a36Sopenharmony_ci minfo->drivers[i] = minfo->drivers[--minfo->drivers_count]; 200062306a36Sopenharmony_ci minfo->drivers_data[i] = minfo->drivers_data[minfo->drivers_count]; 200162306a36Sopenharmony_ci } else 200262306a36Sopenharmony_ci i++; 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci} 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_cistatic void matroxfb_register_device(struct matrox_fb_info* minfo) { 200862306a36Sopenharmony_ci struct matroxfb_driver* drv; 200962306a36Sopenharmony_ci int i = 0; 201062306a36Sopenharmony_ci list_add(&minfo->next_fb, &matroxfb_list); 201162306a36Sopenharmony_ci for (drv = matroxfb_driver_l(matroxfb_driver_list.next); 201262306a36Sopenharmony_ci drv != matroxfb_driver_l(&matroxfb_driver_list); 201362306a36Sopenharmony_ci drv = matroxfb_driver_l(drv->node.next)) { 201462306a36Sopenharmony_ci if (drv->probe) { 201562306a36Sopenharmony_ci void *p = drv->probe(minfo); 201662306a36Sopenharmony_ci if (p) { 201762306a36Sopenharmony_ci minfo->drivers_data[i] = p; 201862306a36Sopenharmony_ci minfo->drivers[i++] = drv; 201962306a36Sopenharmony_ci if (i == MATROXFB_MAX_FB_DRIVERS) 202062306a36Sopenharmony_ci break; 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci minfo->drivers_count = i; 202562306a36Sopenharmony_ci} 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_cistatic void matroxfb_unregister_device(struct matrox_fb_info* minfo) { 202862306a36Sopenharmony_ci int i; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci list_del(&minfo->next_fb); 203162306a36Sopenharmony_ci for (i = 0; i < minfo->drivers_count; i++) { 203262306a36Sopenharmony_ci struct matroxfb_driver* drv = minfo->drivers[i]; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (drv && drv->remove) 203562306a36Sopenharmony_ci drv->remove(minfo, minfo->drivers_data[i]); 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci} 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_cistatic int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) { 204062306a36Sopenharmony_ci struct board* b; 204162306a36Sopenharmony_ci u_int16_t svid; 204262306a36Sopenharmony_ci u_int16_t sid; 204362306a36Sopenharmony_ci struct matrox_fb_info* minfo; 204462306a36Sopenharmony_ci int err; 204562306a36Sopenharmony_ci u_int32_t cmd; 204662306a36Sopenharmony_ci DBG(__func__) 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci err = aperture_remove_conflicting_pci_devices(pdev, "matroxfb"); 204962306a36Sopenharmony_ci if (err) 205062306a36Sopenharmony_ci return err; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci svid = pdev->subsystem_vendor; 205362306a36Sopenharmony_ci sid = pdev->subsystem_device; 205462306a36Sopenharmony_ci for (b = dev_list; b->vendor; b++) { 205562306a36Sopenharmony_ci if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < pdev->revision)) continue; 205662306a36Sopenharmony_ci if (b->svid) 205762306a36Sopenharmony_ci if ((b->svid != svid) || (b->sid != sid)) continue; 205862306a36Sopenharmony_ci break; 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci /* not match... */ 206162306a36Sopenharmony_ci if (!b->vendor) 206262306a36Sopenharmony_ci return -ENODEV; 206362306a36Sopenharmony_ci if (dev > 0) { 206462306a36Sopenharmony_ci /* not requested one... */ 206562306a36Sopenharmony_ci dev--; 206662306a36Sopenharmony_ci return -ENODEV; 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci pci_read_config_dword(pdev, PCI_COMMAND, &cmd); 206962306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 207062306a36Sopenharmony_ci return -1; 207162306a36Sopenharmony_ci } 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci minfo = kzalloc(sizeof(*minfo), GFP_KERNEL); 207462306a36Sopenharmony_ci if (!minfo) 207562306a36Sopenharmony_ci return -ENOMEM; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci minfo->pcidev = pdev; 207862306a36Sopenharmony_ci minfo->dead = 0; 207962306a36Sopenharmony_ci minfo->usecount = 0; 208062306a36Sopenharmony_ci minfo->userusecount = 0; 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci pci_set_drvdata(pdev, minfo); 208362306a36Sopenharmony_ci /* DEVFLAGS */ 208462306a36Sopenharmony_ci minfo->devflags.memtype = memtype; 208562306a36Sopenharmony_ci if (memtype != -1) 208662306a36Sopenharmony_ci noinit = 0; 208762306a36Sopenharmony_ci if (cmd & PCI_COMMAND_MEMORY) { 208862306a36Sopenharmony_ci minfo->devflags.novga = novga; 208962306a36Sopenharmony_ci minfo->devflags.nobios = nobios; 209062306a36Sopenharmony_ci minfo->devflags.noinit = noinit; 209162306a36Sopenharmony_ci /* subsequent heads always needs initialization and must not enable BIOS */ 209262306a36Sopenharmony_ci novga = 1; 209362306a36Sopenharmony_ci nobios = 1; 209462306a36Sopenharmony_ci noinit = 0; 209562306a36Sopenharmony_ci } else { 209662306a36Sopenharmony_ci minfo->devflags.novga = 1; 209762306a36Sopenharmony_ci minfo->devflags.nobios = 1; 209862306a36Sopenharmony_ci minfo->devflags.noinit = 0; 209962306a36Sopenharmony_ci } 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci minfo->devflags.nopciretry = no_pci_retry; 210262306a36Sopenharmony_ci minfo->devflags.mga_24bpp_fix = inv24; 210362306a36Sopenharmony_ci minfo->devflags.precise_width = option_precise_width; 210462306a36Sopenharmony_ci minfo->devflags.sgram = sgram; 210562306a36Sopenharmony_ci minfo->capable.cross4MB = cross4MB; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci spin_lock_init(&minfo->lock.DAC); 210862306a36Sopenharmony_ci spin_lock_init(&minfo->lock.accel); 210962306a36Sopenharmony_ci init_rwsem(&minfo->crtc2.lock); 211062306a36Sopenharmony_ci init_rwsem(&minfo->altout.lock); 211162306a36Sopenharmony_ci mutex_init(&minfo->fbcon.mm_lock); 211262306a36Sopenharmony_ci minfo->irq_flags = 0; 211362306a36Sopenharmony_ci init_waitqueue_head(&minfo->crtc1.vsync.wait); 211462306a36Sopenharmony_ci init_waitqueue_head(&minfo->crtc2.vsync.wait); 211562306a36Sopenharmony_ci minfo->crtc1.panpos = -1; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci err = initMatrox2(minfo, b); 211862306a36Sopenharmony_ci if (!err) { 211962306a36Sopenharmony_ci matroxfb_register_device(minfo); 212062306a36Sopenharmony_ci return 0; 212162306a36Sopenharmony_ci } 212262306a36Sopenharmony_ci kfree(minfo); 212362306a36Sopenharmony_ci return -1; 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_cistatic void pci_remove_matrox(struct pci_dev* pdev) { 212762306a36Sopenharmony_ci struct matrox_fb_info* minfo; 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci minfo = pci_get_drvdata(pdev); 213062306a36Sopenharmony_ci matroxfb_remove(minfo, 1); 213162306a36Sopenharmony_ci} 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_cistatic const struct pci_device_id matroxfb_devices[] = { 213462306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM 213562306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 213662306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 213762306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 213862306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 213962306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 214062306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 214162306a36Sopenharmony_ci#endif 214262306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MYSTIQUE 214362306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 214462306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 214562306a36Sopenharmony_ci#endif 214662306a36Sopenharmony_ci#ifdef CONFIG_FB_MATROX_G 214762306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 214862306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 214962306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 215062306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 215162306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 215262306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 215362306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, 0x0532, 215462306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 215562306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 215662306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 215762306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 215862306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 215962306a36Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, 216062306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 216162306a36Sopenharmony_ci#endif 216262306a36Sopenharmony_ci {0, 0, 216362306a36Sopenharmony_ci 0, 0, 0, 0, 0} 216462306a36Sopenharmony_ci}; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, matroxfb_devices); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_cistatic struct pci_driver matroxfb_driver = { 217062306a36Sopenharmony_ci .name = "matroxfb", 217162306a36Sopenharmony_ci .id_table = matroxfb_devices, 217262306a36Sopenharmony_ci .probe = matroxfb_probe, 217362306a36Sopenharmony_ci .remove = pci_remove_matrox, 217462306a36Sopenharmony_ci}; 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci/* **************************** init-time only **************************** */ 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci#define RSResolution(X) ((X) & 0x0F) 217962306a36Sopenharmony_ci#define RS640x400 1 218062306a36Sopenharmony_ci#define RS640x480 2 218162306a36Sopenharmony_ci#define RS800x600 3 218262306a36Sopenharmony_ci#define RS1024x768 4 218362306a36Sopenharmony_ci#define RS1280x1024 5 218462306a36Sopenharmony_ci#define RS1600x1200 6 218562306a36Sopenharmony_ci#define RS768x576 7 218662306a36Sopenharmony_ci#define RS960x720 8 218762306a36Sopenharmony_ci#define RS1152x864 9 218862306a36Sopenharmony_ci#define RS1408x1056 10 218962306a36Sopenharmony_ci#define RS640x350 11 219062306a36Sopenharmony_ci#define RS1056x344 12 /* 132 x 43 text */ 219162306a36Sopenharmony_ci#define RS1056x400 13 /* 132 x 50 text */ 219262306a36Sopenharmony_ci#define RS1056x480 14 /* 132 x 60 text */ 219362306a36Sopenharmony_ci#define RSNoxNo 15 219462306a36Sopenharmony_ci/* 10-FF */ 219562306a36Sopenharmony_cistatic struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = { 219662306a36Sopenharmony_ci { 640, 400, 48, 16, 39, 8, 96, 2, 70 }, 219762306a36Sopenharmony_ci { 640, 480, 48, 16, 33, 10, 96, 2, 60 }, 219862306a36Sopenharmony_ci { 800, 600, 144, 24, 28, 8, 112, 6, 60 }, 219962306a36Sopenharmony_ci { 1024, 768, 160, 32, 30, 4, 128, 4, 60 }, 220062306a36Sopenharmony_ci { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 }, 220162306a36Sopenharmony_ci { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 }, 220262306a36Sopenharmony_ci { 768, 576, 144, 16, 28, 6, 112, 4, 60 }, 220362306a36Sopenharmony_ci { 960, 720, 144, 24, 28, 8, 112, 4, 60 }, 220462306a36Sopenharmony_ci { 1152, 864, 192, 32, 30, 4, 128, 4, 60 }, 220562306a36Sopenharmony_ci { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 }, 220662306a36Sopenharmony_ci { 640, 350, 48, 16, 39, 8, 96, 2, 70 }, 220762306a36Sopenharmony_ci { 1056, 344, 96, 24, 59, 44, 160, 2, 70 }, 220862306a36Sopenharmony_ci { 1056, 400, 96, 24, 39, 8, 160, 2, 70 }, 220962306a36Sopenharmony_ci { 1056, 480, 96, 24, 36, 12, 160, 3, 60 }, 221062306a36Sopenharmony_ci { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 } 221162306a36Sopenharmony_ci}; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci#define RSCreate(X,Y) ((X) | ((Y) << 8)) 221462306a36Sopenharmony_cistatic struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = { 221562306a36Sopenharmony_ci/* default must be first */ 221662306a36Sopenharmony_ci { ~0, RSCreate(RSNoxNo, RS8bpp ) }, 221762306a36Sopenharmony_ci { 0x101, RSCreate(RS640x480, RS8bpp ) }, 221862306a36Sopenharmony_ci { 0x100, RSCreate(RS640x400, RS8bpp ) }, 221962306a36Sopenharmony_ci { 0x180, RSCreate(RS768x576, RS8bpp ) }, 222062306a36Sopenharmony_ci { 0x103, RSCreate(RS800x600, RS8bpp ) }, 222162306a36Sopenharmony_ci { 0x188, RSCreate(RS960x720, RS8bpp ) }, 222262306a36Sopenharmony_ci { 0x105, RSCreate(RS1024x768, RS8bpp ) }, 222362306a36Sopenharmony_ci { 0x190, RSCreate(RS1152x864, RS8bpp ) }, 222462306a36Sopenharmony_ci { 0x107, RSCreate(RS1280x1024, RS8bpp ) }, 222562306a36Sopenharmony_ci { 0x198, RSCreate(RS1408x1056, RS8bpp ) }, 222662306a36Sopenharmony_ci { 0x11C, RSCreate(RS1600x1200, RS8bpp ) }, 222762306a36Sopenharmony_ci { 0x110, RSCreate(RS640x480, RS15bpp) }, 222862306a36Sopenharmony_ci { 0x181, RSCreate(RS768x576, RS15bpp) }, 222962306a36Sopenharmony_ci { 0x113, RSCreate(RS800x600, RS15bpp) }, 223062306a36Sopenharmony_ci { 0x189, RSCreate(RS960x720, RS15bpp) }, 223162306a36Sopenharmony_ci { 0x116, RSCreate(RS1024x768, RS15bpp) }, 223262306a36Sopenharmony_ci { 0x191, RSCreate(RS1152x864, RS15bpp) }, 223362306a36Sopenharmony_ci { 0x119, RSCreate(RS1280x1024, RS15bpp) }, 223462306a36Sopenharmony_ci { 0x199, RSCreate(RS1408x1056, RS15bpp) }, 223562306a36Sopenharmony_ci { 0x11D, RSCreate(RS1600x1200, RS15bpp) }, 223662306a36Sopenharmony_ci { 0x111, RSCreate(RS640x480, RS16bpp) }, 223762306a36Sopenharmony_ci { 0x182, RSCreate(RS768x576, RS16bpp) }, 223862306a36Sopenharmony_ci { 0x114, RSCreate(RS800x600, RS16bpp) }, 223962306a36Sopenharmony_ci { 0x18A, RSCreate(RS960x720, RS16bpp) }, 224062306a36Sopenharmony_ci { 0x117, RSCreate(RS1024x768, RS16bpp) }, 224162306a36Sopenharmony_ci { 0x192, RSCreate(RS1152x864, RS16bpp) }, 224262306a36Sopenharmony_ci { 0x11A, RSCreate(RS1280x1024, RS16bpp) }, 224362306a36Sopenharmony_ci { 0x19A, RSCreate(RS1408x1056, RS16bpp) }, 224462306a36Sopenharmony_ci { 0x11E, RSCreate(RS1600x1200, RS16bpp) }, 224562306a36Sopenharmony_ci { 0x1B2, RSCreate(RS640x480, RS24bpp) }, 224662306a36Sopenharmony_ci { 0x184, RSCreate(RS768x576, RS24bpp) }, 224762306a36Sopenharmony_ci { 0x1B5, RSCreate(RS800x600, RS24bpp) }, 224862306a36Sopenharmony_ci { 0x18C, RSCreate(RS960x720, RS24bpp) }, 224962306a36Sopenharmony_ci { 0x1B8, RSCreate(RS1024x768, RS24bpp) }, 225062306a36Sopenharmony_ci { 0x194, RSCreate(RS1152x864, RS24bpp) }, 225162306a36Sopenharmony_ci { 0x1BB, RSCreate(RS1280x1024, RS24bpp) }, 225262306a36Sopenharmony_ci { 0x19C, RSCreate(RS1408x1056, RS24bpp) }, 225362306a36Sopenharmony_ci { 0x1BF, RSCreate(RS1600x1200, RS24bpp) }, 225462306a36Sopenharmony_ci { 0x112, RSCreate(RS640x480, RS32bpp) }, 225562306a36Sopenharmony_ci { 0x183, RSCreate(RS768x576, RS32bpp) }, 225662306a36Sopenharmony_ci { 0x115, RSCreate(RS800x600, RS32bpp) }, 225762306a36Sopenharmony_ci { 0x18B, RSCreate(RS960x720, RS32bpp) }, 225862306a36Sopenharmony_ci { 0x118, RSCreate(RS1024x768, RS32bpp) }, 225962306a36Sopenharmony_ci { 0x193, RSCreate(RS1152x864, RS32bpp) }, 226062306a36Sopenharmony_ci { 0x11B, RSCreate(RS1280x1024, RS32bpp) }, 226162306a36Sopenharmony_ci { 0x19B, RSCreate(RS1408x1056, RS32bpp) }, 226262306a36Sopenharmony_ci { 0x11F, RSCreate(RS1600x1200, RS32bpp) }, 226362306a36Sopenharmony_ci { 0x010, RSCreate(RS640x350, RS4bpp ) }, 226462306a36Sopenharmony_ci { 0x012, RSCreate(RS640x480, RS4bpp ) }, 226562306a36Sopenharmony_ci { 0x102, RSCreate(RS800x600, RS4bpp ) }, 226662306a36Sopenharmony_ci { 0x104, RSCreate(RS1024x768, RS4bpp ) }, 226762306a36Sopenharmony_ci { 0x106, RSCreate(RS1280x1024, RS4bpp ) }, 226862306a36Sopenharmony_ci { 0, 0 }}; 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_cistatic void __init matroxfb_init_params(void) { 227162306a36Sopenharmony_ci /* fh from kHz to Hz */ 227262306a36Sopenharmony_ci if (fh < 1000) 227362306a36Sopenharmony_ci fh *= 1000; /* 1kHz minimum */ 227462306a36Sopenharmony_ci /* maxclk */ 227562306a36Sopenharmony_ci if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */ 227662306a36Sopenharmony_ci if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */ 227762306a36Sopenharmony_ci /* fix VESA number */ 227862306a36Sopenharmony_ci if (vesa != ~0) 227962306a36Sopenharmony_ci vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */ 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci /* static settings */ 228262306a36Sopenharmony_ci for (RSptr = vesamap; RSptr->vesa; RSptr++) { 228362306a36Sopenharmony_ci if (RSptr->vesa == vesa) break; 228462306a36Sopenharmony_ci } 228562306a36Sopenharmony_ci if (!RSptr->vesa) { 228662306a36Sopenharmony_ci printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa); 228762306a36Sopenharmony_ci RSptr = vesamap; 228862306a36Sopenharmony_ci } 228962306a36Sopenharmony_ci { 229062306a36Sopenharmony_ci int res = RSResolution(RSptr->info)-1; 229162306a36Sopenharmony_ci if (left == ~0) 229262306a36Sopenharmony_ci left = timmings[res].left; 229362306a36Sopenharmony_ci if (!xres) 229462306a36Sopenharmony_ci xres = timmings[res].xres; 229562306a36Sopenharmony_ci if (right == ~0) 229662306a36Sopenharmony_ci right = timmings[res].right; 229762306a36Sopenharmony_ci if (!hslen) 229862306a36Sopenharmony_ci hslen = timmings[res].hslen; 229962306a36Sopenharmony_ci if (upper == ~0) 230062306a36Sopenharmony_ci upper = timmings[res].upper; 230162306a36Sopenharmony_ci if (!yres) 230262306a36Sopenharmony_ci yres = timmings[res].yres; 230362306a36Sopenharmony_ci if (lower == ~0) 230462306a36Sopenharmony_ci lower = timmings[res].lower; 230562306a36Sopenharmony_ci if (!vslen) 230662306a36Sopenharmony_ci vslen = timmings[res].vslen; 230762306a36Sopenharmony_ci if (!(fv||fh||maxclk||pixclock)) 230862306a36Sopenharmony_ci fv = timmings[res].vfreq; 230962306a36Sopenharmony_ci if (depth == -1) 231062306a36Sopenharmony_ci depth = RSDepth(RSptr->info); 231162306a36Sopenharmony_ci } 231262306a36Sopenharmony_ci} 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_cistatic int __init matrox_init(void) { 231562306a36Sopenharmony_ci int err; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci if (fb_modesetting_disabled("matroxfb")) 231862306a36Sopenharmony_ci return -ENODEV; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci matroxfb_init_params(); 232162306a36Sopenharmony_ci err = pci_register_driver(&matroxfb_driver); 232262306a36Sopenharmony_ci dev = -1; /* accept all new devices... */ 232362306a36Sopenharmony_ci return err; 232462306a36Sopenharmony_ci} 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci/* **************************** exit-time only **************************** */ 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_cistatic void __exit matrox_done(void) { 232962306a36Sopenharmony_ci pci_unregister_driver(&matroxfb_driver); 233062306a36Sopenharmony_ci} 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci#ifndef MODULE 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci/* ************************* init in-kernel code ************************** */ 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_cistatic int __init matroxfb_setup(char *options) { 233762306a36Sopenharmony_ci char *this_opt; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci DBG(__func__) 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci if (!options || !*options) 234262306a36Sopenharmony_ci return 0; 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 234562306a36Sopenharmony_ci if (!*this_opt) continue; 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci dprintk("matroxfb_setup: option %s\n", this_opt); 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci if (!strncmp(this_opt, "dev:", 4)) 235062306a36Sopenharmony_ci dev = simple_strtoul(this_opt+4, NULL, 0); 235162306a36Sopenharmony_ci else if (!strncmp(this_opt, "depth:", 6)) { 235262306a36Sopenharmony_ci switch (simple_strtoul(this_opt+6, NULL, 0)) { 235362306a36Sopenharmony_ci case 0: depth = RSText; break; 235462306a36Sopenharmony_ci case 4: depth = RS4bpp; break; 235562306a36Sopenharmony_ci case 8: depth = RS8bpp; break; 235662306a36Sopenharmony_ci case 15:depth = RS15bpp; break; 235762306a36Sopenharmony_ci case 16:depth = RS16bpp; break; 235862306a36Sopenharmony_ci case 24:depth = RS24bpp; break; 235962306a36Sopenharmony_ci case 32:depth = RS32bpp; break; 236062306a36Sopenharmony_ci default: 236162306a36Sopenharmony_ci printk(KERN_ERR "matroxfb: unsupported color depth\n"); 236262306a36Sopenharmony_ci } 236362306a36Sopenharmony_ci } else if (!strncmp(this_opt, "xres:", 5)) 236462306a36Sopenharmony_ci xres = simple_strtoul(this_opt+5, NULL, 0); 236562306a36Sopenharmony_ci else if (!strncmp(this_opt, "yres:", 5)) 236662306a36Sopenharmony_ci yres = simple_strtoul(this_opt+5, NULL, 0); 236762306a36Sopenharmony_ci else if (!strncmp(this_opt, "vslen:", 6)) 236862306a36Sopenharmony_ci vslen = simple_strtoul(this_opt+6, NULL, 0); 236962306a36Sopenharmony_ci else if (!strncmp(this_opt, "hslen:", 6)) 237062306a36Sopenharmony_ci hslen = simple_strtoul(this_opt+6, NULL, 0); 237162306a36Sopenharmony_ci else if (!strncmp(this_opt, "left:", 5)) 237262306a36Sopenharmony_ci left = simple_strtoul(this_opt+5, NULL, 0); 237362306a36Sopenharmony_ci else if (!strncmp(this_opt, "right:", 6)) 237462306a36Sopenharmony_ci right = simple_strtoul(this_opt+6, NULL, 0); 237562306a36Sopenharmony_ci else if (!strncmp(this_opt, "upper:", 6)) 237662306a36Sopenharmony_ci upper = simple_strtoul(this_opt+6, NULL, 0); 237762306a36Sopenharmony_ci else if (!strncmp(this_opt, "lower:", 6)) 237862306a36Sopenharmony_ci lower = simple_strtoul(this_opt+6, NULL, 0); 237962306a36Sopenharmony_ci else if (!strncmp(this_opt, "pixclock:", 9)) 238062306a36Sopenharmony_ci pixclock = simple_strtoul(this_opt+9, NULL, 0); 238162306a36Sopenharmony_ci else if (!strncmp(this_opt, "sync:", 5)) 238262306a36Sopenharmony_ci sync = simple_strtoul(this_opt+5, NULL, 0); 238362306a36Sopenharmony_ci else if (!strncmp(this_opt, "vesa:", 5)) 238462306a36Sopenharmony_ci vesa = simple_strtoul(this_opt+5, NULL, 0); 238562306a36Sopenharmony_ci else if (!strncmp(this_opt, "maxclk:", 7)) 238662306a36Sopenharmony_ci maxclk = simple_strtoul(this_opt+7, NULL, 0); 238762306a36Sopenharmony_ci else if (!strncmp(this_opt, "fh:", 3)) 238862306a36Sopenharmony_ci fh = simple_strtoul(this_opt+3, NULL, 0); 238962306a36Sopenharmony_ci else if (!strncmp(this_opt, "fv:", 3)) 239062306a36Sopenharmony_ci fv = simple_strtoul(this_opt+3, NULL, 0); 239162306a36Sopenharmony_ci else if (!strncmp(this_opt, "mem:", 4)) 239262306a36Sopenharmony_ci mem = simple_strtoul(this_opt+4, NULL, 0); 239362306a36Sopenharmony_ci else if (!strncmp(this_opt, "mode:", 5)) 239462306a36Sopenharmony_ci strscpy(videomode, this_opt + 5, sizeof(videomode)); 239562306a36Sopenharmony_ci else if (!strncmp(this_opt, "outputs:", 8)) 239662306a36Sopenharmony_ci strscpy(outputs, this_opt + 8, sizeof(outputs)); 239762306a36Sopenharmony_ci else if (!strncmp(this_opt, "dfp:", 4)) { 239862306a36Sopenharmony_ci dfp_type = simple_strtoul(this_opt+4, NULL, 0); 239962306a36Sopenharmony_ci dfp = 1; 240062306a36Sopenharmony_ci } 240162306a36Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 240262306a36Sopenharmony_ci else if (!strncmp(this_opt, "vmode:", 6)) { 240362306a36Sopenharmony_ci unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); 240462306a36Sopenharmony_ci if (vmode > 0 && vmode <= VMODE_MAX) 240562306a36Sopenharmony_ci default_vmode = vmode; 240662306a36Sopenharmony_ci } else if (!strncmp(this_opt, "cmode:", 6)) { 240762306a36Sopenharmony_ci unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); 240862306a36Sopenharmony_ci switch (cmode) { 240962306a36Sopenharmony_ci case 0: 241062306a36Sopenharmony_ci case 8: 241162306a36Sopenharmony_ci default_cmode = CMODE_8; 241262306a36Sopenharmony_ci break; 241362306a36Sopenharmony_ci case 15: 241462306a36Sopenharmony_ci case 16: 241562306a36Sopenharmony_ci default_cmode = CMODE_16; 241662306a36Sopenharmony_ci break; 241762306a36Sopenharmony_ci case 24: 241862306a36Sopenharmony_ci case 32: 241962306a36Sopenharmony_ci default_cmode = CMODE_32; 242062306a36Sopenharmony_ci break; 242162306a36Sopenharmony_ci } 242262306a36Sopenharmony_ci } 242362306a36Sopenharmony_ci#endif 242462306a36Sopenharmony_ci else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */ 242562306a36Sopenharmony_ci disabled = 1; 242662306a36Sopenharmony_ci else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */ 242762306a36Sopenharmony_ci disabled = 0; 242862306a36Sopenharmony_ci else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */ 242962306a36Sopenharmony_ci sgram = 1; 243062306a36Sopenharmony_ci else if (!strcmp(this_opt, "sdram")) 243162306a36Sopenharmony_ci sgram = 0; 243262306a36Sopenharmony_ci else if (!strncmp(this_opt, "memtype:", 8)) 243362306a36Sopenharmony_ci memtype = simple_strtoul(this_opt+8, NULL, 0); 243462306a36Sopenharmony_ci else { 243562306a36Sopenharmony_ci int value = 1; 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci if (!strncmp(this_opt, "no", 2)) { 243862306a36Sopenharmony_ci value = 0; 243962306a36Sopenharmony_ci this_opt += 2; 244062306a36Sopenharmony_ci } 244162306a36Sopenharmony_ci if (! strcmp(this_opt, "inverse")) 244262306a36Sopenharmony_ci inverse = value; 244362306a36Sopenharmony_ci else if (!strcmp(this_opt, "accel")) 244462306a36Sopenharmony_ci noaccel = !value; 244562306a36Sopenharmony_ci else if (!strcmp(this_opt, "pan")) 244662306a36Sopenharmony_ci nopan = !value; 244762306a36Sopenharmony_ci else if (!strcmp(this_opt, "pciretry")) 244862306a36Sopenharmony_ci no_pci_retry = !value; 244962306a36Sopenharmony_ci else if (!strcmp(this_opt, "vga")) 245062306a36Sopenharmony_ci novga = !value; 245162306a36Sopenharmony_ci else if (!strcmp(this_opt, "bios")) 245262306a36Sopenharmony_ci nobios = !value; 245362306a36Sopenharmony_ci else if (!strcmp(this_opt, "init")) 245462306a36Sopenharmony_ci noinit = !value; 245562306a36Sopenharmony_ci else if (!strcmp(this_opt, "mtrr")) 245662306a36Sopenharmony_ci mtrr = value; 245762306a36Sopenharmony_ci else if (!strcmp(this_opt, "inv24")) 245862306a36Sopenharmony_ci inv24 = value; 245962306a36Sopenharmony_ci else if (!strcmp(this_opt, "cross4MB")) 246062306a36Sopenharmony_ci cross4MB = value; 246162306a36Sopenharmony_ci else if (!strcmp(this_opt, "grayscale")) 246262306a36Sopenharmony_ci grayscale = value; 246362306a36Sopenharmony_ci else if (!strcmp(this_opt, "dfp")) 246462306a36Sopenharmony_ci dfp = value; 246562306a36Sopenharmony_ci else { 246662306a36Sopenharmony_ci strscpy(videomode, this_opt, sizeof(videomode)); 246762306a36Sopenharmony_ci } 246862306a36Sopenharmony_ci } 246962306a36Sopenharmony_ci } 247062306a36Sopenharmony_ci return 0; 247162306a36Sopenharmony_ci} 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_cistatic int __initdata initialized = 0; 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_cistatic int __init matroxfb_init(void) 247662306a36Sopenharmony_ci{ 247762306a36Sopenharmony_ci char *option = NULL; 247862306a36Sopenharmony_ci int err = 0; 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci DBG(__func__) 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci if (fb_get_options("matroxfb", &option)) 248362306a36Sopenharmony_ci return -ENODEV; 248462306a36Sopenharmony_ci matroxfb_setup(option); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci if (disabled) 248762306a36Sopenharmony_ci return -ENXIO; 248862306a36Sopenharmony_ci if (!initialized) { 248962306a36Sopenharmony_ci initialized = 1; 249062306a36Sopenharmony_ci err = matrox_init(); 249162306a36Sopenharmony_ci } 249262306a36Sopenharmony_ci hotplug = 1; 249362306a36Sopenharmony_ci /* never return failure, user can hotplug matrox later... */ 249462306a36Sopenharmony_ci return err; 249562306a36Sopenharmony_ci} 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci#else 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci/* *************************** init module code **************************** */ 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ciMODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); 250262306a36Sopenharmony_ciMODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550"); 250362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_cimodule_param(mem, int, 0); 250662306a36Sopenharmony_ciMODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)"); 250762306a36Sopenharmony_cimodule_param(disabled, int, 0); 250862306a36Sopenharmony_ciMODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled) (default=0)"); 250962306a36Sopenharmony_cimodule_param(noaccel, int, 0); 251062306a36Sopenharmony_ciMODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)"); 251162306a36Sopenharmony_cimodule_param(nopan, int, 0); 251262306a36Sopenharmony_ciMODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)"); 251362306a36Sopenharmony_cimodule_param(no_pci_retry, int, 0); 251462306a36Sopenharmony_ciMODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)"); 251562306a36Sopenharmony_cimodule_param(novga, int, 0); 251662306a36Sopenharmony_ciMODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)"); 251762306a36Sopenharmony_cimodule_param(nobios, int, 0); 251862306a36Sopenharmony_ciMODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); 251962306a36Sopenharmony_cimodule_param(noinit, int, 0); 252062306a36Sopenharmony_ciMODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)"); 252162306a36Sopenharmony_cimodule_param(memtype, int, 0); 252262306a36Sopenharmony_ciMODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.rst for explanation) (default=3 for G200, 0 for G400)"); 252362306a36Sopenharmony_cimodule_param(mtrr, int, 0); 252462306a36Sopenharmony_ciMODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)"); 252562306a36Sopenharmony_cimodule_param(sgram, int, 0); 252662306a36Sopenharmony_ciMODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)"); 252762306a36Sopenharmony_cimodule_param(inv24, int, 0); 252862306a36Sopenharmony_ciMODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)"); 252962306a36Sopenharmony_cimodule_param(inverse, int, 0); 253062306a36Sopenharmony_ciMODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)"); 253162306a36Sopenharmony_cimodule_param(dev, int, 0); 253262306a36Sopenharmony_ciMODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)"); 253362306a36Sopenharmony_cimodule_param(vesa, int, 0); 253462306a36Sopenharmony_ciMODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)"); 253562306a36Sopenharmony_cimodule_param(xres, int, 0); 253662306a36Sopenharmony_ciMODULE_PARM_DESC(xres, "Horizontal resolution (px), overrides xres from vesa (default=vesa)"); 253762306a36Sopenharmony_cimodule_param(yres, int, 0); 253862306a36Sopenharmony_ciMODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)"); 253962306a36Sopenharmony_cimodule_param(upper, int, 0); 254062306a36Sopenharmony_ciMODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)"); 254162306a36Sopenharmony_cimodule_param(lower, int, 0); 254262306a36Sopenharmony_ciMODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)"); 254362306a36Sopenharmony_cimodule_param(vslen, int, 0); 254462306a36Sopenharmony_ciMODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)"); 254562306a36Sopenharmony_cimodule_param(left, int, 0); 254662306a36Sopenharmony_ciMODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)"); 254762306a36Sopenharmony_cimodule_param(right, int, 0); 254862306a36Sopenharmony_ciMODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)"); 254962306a36Sopenharmony_cimodule_param(hslen, int, 0); 255062306a36Sopenharmony_ciMODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)"); 255162306a36Sopenharmony_cimodule_param(pixclock, int, 0); 255262306a36Sopenharmony_ciMODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)"); 255362306a36Sopenharmony_cimodule_param(sync, int, 0); 255462306a36Sopenharmony_ciMODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)"); 255562306a36Sopenharmony_cimodule_param(depth, int, 0); 255662306a36Sopenharmony_ciMODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)"); 255762306a36Sopenharmony_cimodule_param(maxclk, int, 0); 255862306a36Sopenharmony_ciMODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz"); 255962306a36Sopenharmony_cimodule_param(fh, int, 0); 256062306a36Sopenharmony_ciMODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz"); 256162306a36Sopenharmony_cimodule_param(fv, int, 0); 256262306a36Sopenharmony_ciMODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n" 256362306a36Sopenharmony_ci"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\""); 256462306a36Sopenharmony_cimodule_param(grayscale, int, 0); 256562306a36Sopenharmony_ciMODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)"); 256662306a36Sopenharmony_cimodule_param(cross4MB, int, 0); 256762306a36Sopenharmony_ciMODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)"); 256862306a36Sopenharmony_cimodule_param(dfp, int, 0); 256962306a36Sopenharmony_ciMODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)"); 257062306a36Sopenharmony_cimodule_param(dfp_type, int, 0); 257162306a36Sopenharmony_ciMODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)"); 257262306a36Sopenharmony_cimodule_param_string(outputs, outputs, sizeof(outputs), 0); 257362306a36Sopenharmony_ciMODULE_PARM_DESC(outputs, "Specifies which CRTC is mapped to which output (string of up to three letters, consisting of 0 (disabled), 1 (CRTC1), 2 (CRTC2)) (default=111 for Gx50, 101 for G200/G400 with DFP, and 100 for all other devices)"); 257462306a36Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 257562306a36Sopenharmony_cimodule_param_named(vmode, default_vmode, int, 0); 257662306a36Sopenharmony_ciMODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)"); 257762306a36Sopenharmony_cimodule_param_named(cmode, default_cmode, int, 0); 257862306a36Sopenharmony_ciMODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)"); 257962306a36Sopenharmony_ci#endif 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_cistatic int __init matroxfb_init(void){ 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci DBG(__func__) 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci if (disabled) 258662306a36Sopenharmony_ci return -ENXIO; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci if (depth == 0) 258962306a36Sopenharmony_ci depth = RSText; 259062306a36Sopenharmony_ci else if (depth == 4) 259162306a36Sopenharmony_ci depth = RS4bpp; 259262306a36Sopenharmony_ci else if (depth == 8) 259362306a36Sopenharmony_ci depth = RS8bpp; 259462306a36Sopenharmony_ci else if (depth == 15) 259562306a36Sopenharmony_ci depth = RS15bpp; 259662306a36Sopenharmony_ci else if (depth == 16) 259762306a36Sopenharmony_ci depth = RS16bpp; 259862306a36Sopenharmony_ci else if (depth == 24) 259962306a36Sopenharmony_ci depth = RS24bpp; 260062306a36Sopenharmony_ci else if (depth == 32) 260162306a36Sopenharmony_ci depth = RS32bpp; 260262306a36Sopenharmony_ci else if (depth != -1) { 260362306a36Sopenharmony_ci printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth); 260462306a36Sopenharmony_ci depth = -1; 260562306a36Sopenharmony_ci } 260662306a36Sopenharmony_ci matrox_init(); 260762306a36Sopenharmony_ci /* never return failure; user can hotplug matrox later... */ 260862306a36Sopenharmony_ci return 0; 260962306a36Sopenharmony_ci} 261062306a36Sopenharmony_ci#endif /* MODULE */ 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_cimodule_init(matroxfb_init); 261362306a36Sopenharmony_cimodule_exit(matrox_done); 261462306a36Sopenharmony_ciEXPORT_SYMBOL(matroxfb_register_driver); 261562306a36Sopenharmony_ciEXPORT_SYMBOL(matroxfb_unregister_driver); 261662306a36Sopenharmony_ciEXPORT_SYMBOL(matroxfb_wait_for_sync); 261762306a36Sopenharmony_ciEXPORT_SYMBOL(matroxfb_enable_irq); 2618