18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Portions Copyright (c) 2001 Matrox Graphics Inc. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Version: 1.65 2002/08/14 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Contributors: "menion?" <menion@mindless.com> 158c2ecf20Sopenharmony_ci * Betatesting, fixes, ideas 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * "Kurt Garloff" <garloff@suse.de> 188c2ecf20Sopenharmony_ci * Betatesting, fixes, ideas, videomodes, videomodes timmings 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * "Tom Rini" <trini@kernel.crashing.org> 218c2ecf20Sopenharmony_ci * MTRR stuff, PPC cleanups, betatesting, fixes, ideas 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * "Bibek Sahu" <scorpio@dodds.net> 248c2ecf20Sopenharmony_ci * Access device through readb|w|l and write b|w|l 258c2ecf20Sopenharmony_ci * Extensive debugging stuff 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * "Daniel Haun" <haund@usa.net> 288c2ecf20Sopenharmony_ci * Testing, hardware cursor fixes 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * "Scott Wood" <sawst46+@pitt.edu> 318c2ecf20Sopenharmony_ci * Fixes 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de> 348c2ecf20Sopenharmony_ci * Betatesting 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * "Kelly French" <targon@hazmat.com> 378c2ecf20Sopenharmony_ci * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es> 388c2ecf20Sopenharmony_ci * Betatesting, bug reporting 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * "Pablo Bianucci" <pbian@pccp.com.ar> 418c2ecf20Sopenharmony_ci * Fixes, ideas, betatesting 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es> 448c2ecf20Sopenharmony_ci * Fixes, enhandcements, ideas, betatesting 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp> 478c2ecf20Sopenharmony_ci * PPC betatesting, PPC support, backward compatibility 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * "Paul Womar" <Paul@pwomar.demon.co.uk> 508c2ecf20Sopenharmony_ci * "Owen Waller" <O.Waller@ee.qub.ac.uk> 518c2ecf20Sopenharmony_ci * PPC betatesting 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * "Thomas Pornin" <pornin@bolet.ens.fr> 548c2ecf20Sopenharmony_ci * Alpha betatesting 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * "Pieter van Leuven" <pvl@iae.nl> 578c2ecf20Sopenharmony_ci * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de> 588c2ecf20Sopenharmony_ci * G100 testing 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * "H. Peter Arvin" <hpa@transmeta.com> 618c2ecf20Sopenharmony_ci * Ideas 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * "Cort Dougan" <cort@cs.nmt.edu> 648c2ecf20Sopenharmony_ci * CHRP fixes and PReP cleanup 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * "Mark Vojkovich" <mvojkovi@ucsd.edu> 678c2ecf20Sopenharmony_ci * G400 support 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * "Samuel Hocevar" <sam@via.ecp.fr> 708c2ecf20Sopenharmony_ci * Fixes 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * "Anton Altaparmakov" <AntonA@bigfoot.com> 738c2ecf20Sopenharmony_ci * G400 MAX/non-MAX distinction 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com> 768c2ecf20Sopenharmony_ci * memtype extension (needed for GXT130P RS/6000 adapter) 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * "Uns Lider" <unslider@miranda.org> 798c2ecf20Sopenharmony_ci * G100 PLNWT fixes 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * "Denis Zaitsev" <zzz@cd-club.ru> 828c2ecf20Sopenharmony_ci * Fixes 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * "Mike Pieper" <mike@pieper-family.de> 858c2ecf20Sopenharmony_ci * TVOut enhandcements, V4L2 control interface. 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * "Diego Biurrun" <diego@biurrun.de> 888c2ecf20Sopenharmony_ci * DFP testing 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * (following author is not in any relation with this code, but his code 918c2ecf20Sopenharmony_ci * is included in this driver) 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * Based on framebuffer driver for VBE 2.0 compliant graphic boards 948c2ecf20Sopenharmony_ci * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * (following author is not in any relation with this code, but his ideas 978c2ecf20Sopenharmony_ci * were used when writing this driver) 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk> 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#include <linux/version.h> 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#include "matroxfb_base.h" 1068c2ecf20Sopenharmony_ci#include "matroxfb_misc.h" 1078c2ecf20Sopenharmony_ci#include "matroxfb_accel.h" 1088c2ecf20Sopenharmony_ci#include "matroxfb_DAC1064.h" 1098c2ecf20Sopenharmony_ci#include "matroxfb_Ti3026.h" 1108c2ecf20Sopenharmony_ci#include "matroxfb_maven.h" 1118c2ecf20Sopenharmony_ci#include "matroxfb_crtc2.h" 1128c2ecf20Sopenharmony_ci#include "matroxfb_g450.h" 1138c2ecf20Sopenharmony_ci#include <linux/matroxfb.h> 1148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 1158c2ecf20Sopenharmony_ci#include <linux/nvram.h> 1168c2ecf20Sopenharmony_ci#include <linux/slab.h> 1178c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 1208c2ecf20Sopenharmony_ci#include <asm/machdep.h> 1218c2ecf20Sopenharmony_cistatic int default_vmode = VMODE_NVRAM; 1228c2ecf20Sopenharmony_cistatic int default_cmode = CMODE_NVRAM; 1238c2ecf20Sopenharmony_ci#endif 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void matroxfb_unregister_device(struct matrox_fb_info* minfo); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* 1308c2ecf20Sopenharmony_ci * card parameters 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct fb_var_screeninfo vesafb_defined = { 1368c2ecf20Sopenharmony_ci 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/ 1378c2ecf20Sopenharmony_ci 0,0, /* virtual -> visible no offset */ 1388c2ecf20Sopenharmony_ci 8, /* depth -> load bits_per_pixel */ 1398c2ecf20Sopenharmony_ci 0, /* greyscale ? */ 1408c2ecf20Sopenharmony_ci {0,0,0}, /* R */ 1418c2ecf20Sopenharmony_ci {0,0,0}, /* G */ 1428c2ecf20Sopenharmony_ci {0,0,0}, /* B */ 1438c2ecf20Sopenharmony_ci {0,0,0}, /* transparency */ 1448c2ecf20Sopenharmony_ci 0, /* standard pixel format */ 1458c2ecf20Sopenharmony_ci FB_ACTIVATE_NOW, 1468c2ecf20Sopenharmony_ci -1,-1, 1478c2ecf20Sopenharmony_ci FB_ACCELF_TEXT, /* accel flags */ 1488c2ecf20Sopenharmony_ci 39721L,48L,16L,33L,10L, 1498c2ecf20Sopenharmony_ci 96L,2L,~0, /* No sync info */ 1508c2ecf20Sopenharmony_ci FB_VMODE_NONINTERLACED, 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */ 1568c2ecf20Sopenharmony_cistatic void update_crtc2(struct matrox_fb_info *minfo, unsigned int pos) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct matroxfb_dh_fb_info *info = minfo->crtc2.info; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Make sure that displays are compatible */ 1618c2ecf20Sopenharmony_ci if (info && (info->fbcon.var.bits_per_pixel == minfo->fbcon.var.bits_per_pixel) 1628c2ecf20Sopenharmony_ci && (info->fbcon.var.xres_virtual == minfo->fbcon.var.xres_virtual) 1638c2ecf20Sopenharmony_ci && (info->fbcon.var.green.length == minfo->fbcon.var.green.length) 1648c2ecf20Sopenharmony_ci ) { 1658c2ecf20Sopenharmony_ci switch (minfo->fbcon.var.bits_per_pixel) { 1668c2ecf20Sopenharmony_ci case 16: 1678c2ecf20Sopenharmony_ci case 32: 1688c2ecf20Sopenharmony_ci pos = pos * 8; 1698c2ecf20Sopenharmony_ci if (info->interlaced) { 1708c2ecf20Sopenharmony_ci mga_outl(0x3C2C, pos); 1718c2ecf20Sopenharmony_ci mga_outl(0x3C28, pos + minfo->fbcon.var.xres_virtual * minfo->fbcon.var.bits_per_pixel / 8); 1728c2ecf20Sopenharmony_ci } else { 1738c2ecf20Sopenharmony_ci mga_outl(0x3C28, pos); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void matroxfb_crtc1_panpos(struct matrox_fb_info *minfo) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci if (minfo->crtc1.panpos >= 0) { 1838c2ecf20Sopenharmony_ci unsigned long flags; 1848c2ecf20Sopenharmony_ci int panpos; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci matroxfb_DAC_lock_irqsave(flags); 1878c2ecf20Sopenharmony_ci panpos = minfo->crtc1.panpos; 1888c2ecf20Sopenharmony_ci if (panpos >= 0) { 1898c2ecf20Sopenharmony_ci unsigned int extvga_reg; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci minfo->crtc1.panpos = -1; /* No update pending anymore */ 1928c2ecf20Sopenharmony_ci extvga_reg = mga_inb(M_EXTVGA_INDEX); 1938c2ecf20Sopenharmony_ci mga_setr(M_EXTVGA_INDEX, 0x00, panpos); 1948c2ecf20Sopenharmony_ci if (extvga_reg != 0x00) { 1958c2ecf20Sopenharmony_ci mga_outb(M_EXTVGA_INDEX, extvga_reg); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci matroxfb_DAC_unlock_irqrestore(flags); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic irqreturn_t matrox_irq(int irq, void *dev_id) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci u_int32_t status; 2058c2ecf20Sopenharmony_ci int handled = 0; 2068c2ecf20Sopenharmony_ci struct matrox_fb_info *minfo = dev_id; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci status = mga_inl(M_STATUS); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (status & 0x20) { 2118c2ecf20Sopenharmony_ci mga_outl(M_ICLEAR, 0x20); 2128c2ecf20Sopenharmony_ci minfo->crtc1.vsync.cnt++; 2138c2ecf20Sopenharmony_ci matroxfb_crtc1_panpos(minfo); 2148c2ecf20Sopenharmony_ci wake_up_interruptible(&minfo->crtc1.vsync.wait); 2158c2ecf20Sopenharmony_ci handled = 1; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci if (status & 0x200) { 2188c2ecf20Sopenharmony_ci mga_outl(M_ICLEAR, 0x200); 2198c2ecf20Sopenharmony_ci minfo->crtc2.vsync.cnt++; 2208c2ecf20Sopenharmony_ci wake_up_interruptible(&minfo->crtc2.vsync.wait); 2218c2ecf20Sopenharmony_ci handled = 1; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciint matroxfb_enable_irq(struct matrox_fb_info *minfo, int reenable) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci u_int32_t bm; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) 2318c2ecf20Sopenharmony_ci bm = 0x220; 2328c2ecf20Sopenharmony_ci else 2338c2ecf20Sopenharmony_ci bm = 0x020; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!test_and_set_bit(0, &minfo->irq_flags)) { 2368c2ecf20Sopenharmony_ci if (request_irq(minfo->pcidev->irq, matrox_irq, 2378c2ecf20Sopenharmony_ci IRQF_SHARED, "matroxfb", minfo)) { 2388c2ecf20Sopenharmony_ci clear_bit(0, &minfo->irq_flags); 2398c2ecf20Sopenharmony_ci return -EINVAL; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci /* Clear any pending field interrupts */ 2428c2ecf20Sopenharmony_ci mga_outl(M_ICLEAR, bm); 2438c2ecf20Sopenharmony_ci mga_outl(M_IEN, mga_inl(M_IEN) | bm); 2448c2ecf20Sopenharmony_ci } else if (reenable) { 2458c2ecf20Sopenharmony_ci u_int32_t ien; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ien = mga_inl(M_IEN); 2488c2ecf20Sopenharmony_ci if ((ien & bm) != bm) { 2498c2ecf20Sopenharmony_ci printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien); 2508c2ecf20Sopenharmony_ci mga_outl(M_IEN, ien | bm); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void matroxfb_disable_irq(struct matrox_fb_info *minfo) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci if (test_and_clear_bit(0, &minfo->irq_flags)) { 2598c2ecf20Sopenharmony_ci /* Flush pending pan-at-vbl request... */ 2608c2ecf20Sopenharmony_ci matroxfb_crtc1_panpos(minfo); 2618c2ecf20Sopenharmony_ci if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) 2628c2ecf20Sopenharmony_ci mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220); 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20); 2658c2ecf20Sopenharmony_ci free_irq(minfo->pcidev->irq, minfo); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ciint matroxfb_wait_for_sync(struct matrox_fb_info *minfo, u_int32_t crtc) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct matrox_vsync *vs; 2728c2ecf20Sopenharmony_ci unsigned int cnt; 2738c2ecf20Sopenharmony_ci int ret; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci switch (crtc) { 2768c2ecf20Sopenharmony_ci case 0: 2778c2ecf20Sopenharmony_ci vs = &minfo->crtc1.vsync; 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case 1: 2808c2ecf20Sopenharmony_ci if (minfo->devflags.accelerator != FB_ACCEL_MATROX_MGAG400) { 2818c2ecf20Sopenharmony_ci return -ENODEV; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci vs = &minfo->crtc2.vsync; 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci default: 2868c2ecf20Sopenharmony_ci return -ENODEV; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci ret = matroxfb_enable_irq(minfo, 0); 2898c2ecf20Sopenharmony_ci if (ret) { 2908c2ecf20Sopenharmony_ci return ret; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci cnt = vs->cnt; 2948c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10); 2958c2ecf20Sopenharmony_ci if (ret < 0) { 2968c2ecf20Sopenharmony_ci return ret; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci if (ret == 0) { 2998c2ecf20Sopenharmony_ci matroxfb_enable_irq(minfo, 1); 3008c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* --------------------------------------------------------------------- */ 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void matrox_pan_var(struct matrox_fb_info *minfo, 3088c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci unsigned int pos; 3118c2ecf20Sopenharmony_ci unsigned short p0, p1, p2; 3128c2ecf20Sopenharmony_ci unsigned int p3; 3138c2ecf20Sopenharmony_ci int vbl; 3148c2ecf20Sopenharmony_ci unsigned long flags; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci CRITFLAGS 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci DBG(__func__) 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (minfo->dead) 3218c2ecf20Sopenharmony_ci return; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci minfo->fbcon.var.xoffset = var->xoffset; 3248c2ecf20Sopenharmony_ci minfo->fbcon.var.yoffset = var->yoffset; 3258c2ecf20Sopenharmony_ci pos = (minfo->fbcon.var.yoffset * minfo->fbcon.var.xres_virtual + minfo->fbcon.var.xoffset) * minfo->curr.final_bppShift / 32; 3268c2ecf20Sopenharmony_ci pos += minfo->curr.ydstorg.chunks; 3278c2ecf20Sopenharmony_ci p0 = minfo->hw.CRTC[0x0D] = pos & 0xFF; 3288c2ecf20Sopenharmony_ci p1 = minfo->hw.CRTC[0x0C] = (pos & 0xFF00) >> 8; 3298c2ecf20Sopenharmony_ci p2 = minfo->hw.CRTCEXT[0] = (minfo->hw.CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); 3308c2ecf20Sopenharmony_ci p3 = minfo->hw.CRTCEXT[8] = pos >> 21; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */ 3338c2ecf20Sopenharmony_ci vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(minfo, 0) == 0); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci CRITBEGIN 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci matroxfb_DAC_lock_irqsave(flags); 3388c2ecf20Sopenharmony_ci mga_setr(M_CRTC_INDEX, 0x0D, p0); 3398c2ecf20Sopenharmony_ci mga_setr(M_CRTC_INDEX, 0x0C, p1); 3408c2ecf20Sopenharmony_ci if (minfo->devflags.support32MB) 3418c2ecf20Sopenharmony_ci mga_setr(M_EXTVGA_INDEX, 0x08, p3); 3428c2ecf20Sopenharmony_ci if (vbl) { 3438c2ecf20Sopenharmony_ci minfo->crtc1.panpos = p2; 3448c2ecf20Sopenharmony_ci } else { 3458c2ecf20Sopenharmony_ci /* Abort any pending change */ 3468c2ecf20Sopenharmony_ci minfo->crtc1.panpos = -1; 3478c2ecf20Sopenharmony_ci mga_setr(M_EXTVGA_INDEX, 0x00, p2); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci matroxfb_DAC_unlock_irqrestore(flags); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci update_crtc2(minfo, pos); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci CRITEND 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void matroxfb_remove(struct matrox_fb_info *minfo, int dummy) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci /* Currently we are holding big kernel lock on all dead & usecount updates. 3598c2ecf20Sopenharmony_ci * Destroy everything after all users release it. Especially do not unregister 3608c2ecf20Sopenharmony_ci * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check 3618c2ecf20Sopenharmony_ci * for device unplugged when in use. 3628c2ecf20Sopenharmony_ci * In future we should point mmio.vbase & video.vbase somewhere where we can 3638c2ecf20Sopenharmony_ci * write data without causing too much damage... 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci minfo->dead = 1; 3678c2ecf20Sopenharmony_ci if (minfo->usecount) { 3688c2ecf20Sopenharmony_ci /* destroy it later */ 3698c2ecf20Sopenharmony_ci return; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci matroxfb_unregister_device(minfo); 3728c2ecf20Sopenharmony_ci unregister_framebuffer(&minfo->fbcon); 3738c2ecf20Sopenharmony_ci matroxfb_g450_shutdown(minfo); 3748c2ecf20Sopenharmony_ci arch_phys_wc_del(minfo->wc_cookie); 3758c2ecf20Sopenharmony_ci iounmap(minfo->mmio.vbase.vaddr); 3768c2ecf20Sopenharmony_ci iounmap(minfo->video.vbase.vaddr); 3778c2ecf20Sopenharmony_ci release_mem_region(minfo->video.base, minfo->video.len_maximum); 3788c2ecf20Sopenharmony_ci release_mem_region(minfo->mmio.base, 16384); 3798c2ecf20Sopenharmony_ci kfree(minfo); 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* 3838c2ecf20Sopenharmony_ci * Open/Release the frame buffer device 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int matroxfb_open(struct fb_info *info, int user) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci DBG_LOOP(__func__) 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (minfo->dead) { 3938c2ecf20Sopenharmony_ci return -ENXIO; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci minfo->usecount++; 3968c2ecf20Sopenharmony_ci if (user) { 3978c2ecf20Sopenharmony_ci minfo->userusecount++; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci return(0); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int matroxfb_release(struct fb_info *info, int user) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci DBG_LOOP(__func__) 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (user) { 4098c2ecf20Sopenharmony_ci if (0 == --minfo->userusecount) { 4108c2ecf20Sopenharmony_ci matroxfb_disable_irq(minfo); 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci if (!(--minfo->usecount) && minfo->dead) { 4148c2ecf20Sopenharmony_ci matroxfb_remove(minfo, 0); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci return(0); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int matroxfb_pan_display(struct fb_var_screeninfo *var, 4208c2ecf20Sopenharmony_ci struct fb_info* info) { 4218c2ecf20Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci DBG(__func__) 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci matrox_pan_var(minfo, var); 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int matroxfb_get_final_bppShift(const struct matrox_fb_info *minfo, 4308c2ecf20Sopenharmony_ci int bpp) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci int bppshft2; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci DBG(__func__) 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci bppshft2 = bpp; 4378c2ecf20Sopenharmony_ci if (!bppshft2) { 4388c2ecf20Sopenharmony_ci return 8; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci if (isInterleave(minfo)) 4418c2ecf20Sopenharmony_ci bppshft2 >>= 1; 4428c2ecf20Sopenharmony_ci if (minfo->devflags.video64bits) 4438c2ecf20Sopenharmony_ci bppshft2 >>= 1; 4448c2ecf20Sopenharmony_ci return bppshft2; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int matroxfb_test_and_set_rounding(const struct matrox_fb_info *minfo, 4488c2ecf20Sopenharmony_ci int xres, int bpp) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci int over; 4518c2ecf20Sopenharmony_ci int rounding; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci DBG(__func__) 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci switch (bpp) { 4568c2ecf20Sopenharmony_ci case 0: return xres; 4578c2ecf20Sopenharmony_ci case 4: rounding = 128; 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */ 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci case 16: rounding = 32; 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */ 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci default: rounding = 16; 4668c2ecf20Sopenharmony_ci /* on G400, 16 really does not work */ 4678c2ecf20Sopenharmony_ci if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) 4688c2ecf20Sopenharmony_ci rounding = 32; 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci if (isInterleave(minfo)) { 4728c2ecf20Sopenharmony_ci rounding *= 2; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci over = xres % rounding; 4758c2ecf20Sopenharmony_ci if (over) 4768c2ecf20Sopenharmony_ci xres += rounding-over; 4778c2ecf20Sopenharmony_ci return xres; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic int matroxfb_pitch_adjust(const struct matrox_fb_info *minfo, int xres, 4818c2ecf20Sopenharmony_ci int bpp) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci const int* width; 4848c2ecf20Sopenharmony_ci int xres_new; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci DBG(__func__) 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (!bpp) return xres; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci width = minfo->capable.vxres; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (minfo->devflags.precise_width) { 4938c2ecf20Sopenharmony_ci while (*width) { 4948c2ecf20Sopenharmony_ci if ((*width >= xres) && (matroxfb_test_and_set_rounding(minfo, *width, bpp) == *width)) { 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci width++; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci xres_new = *width; 5008c2ecf20Sopenharmony_ci } else { 5018c2ecf20Sopenharmony_ci xres_new = matroxfb_test_and_set_rounding(minfo, xres, bpp); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci return xres_new; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci DBG(__func__) 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 5118c2ecf20Sopenharmony_ci case 4: 5128c2ecf20Sopenharmony_ci return 16; /* pseudocolor... 16 entries HW palette */ 5138c2ecf20Sopenharmony_ci case 8: 5148c2ecf20Sopenharmony_ci return 256; /* pseudocolor... 256 entries HW palette */ 5158c2ecf20Sopenharmony_ci case 16: 5168c2ecf20Sopenharmony_ci return 16; /* directcolor... 16 entries SW palette */ 5178c2ecf20Sopenharmony_ci /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ 5188c2ecf20Sopenharmony_ci case 24: 5198c2ecf20Sopenharmony_ci return 16; /* directcolor... 16 entries SW palette */ 5208c2ecf20Sopenharmony_ci /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ 5218c2ecf20Sopenharmony_ci case 32: 5228c2ecf20Sopenharmony_ci return 16; /* directcolor... 16 entries SW palette */ 5238c2ecf20Sopenharmony_ci /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci return 16; /* return something reasonable... or panic()? */ 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int matroxfb_decode_var(const struct matrox_fb_info *minfo, 5298c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var, int *visual, 5308c2ecf20Sopenharmony_ci int *video_cmap_len, unsigned int* ydstorg) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct RGBT { 5338c2ecf20Sopenharmony_ci unsigned char bpp; 5348c2ecf20Sopenharmony_ci struct { 5358c2ecf20Sopenharmony_ci unsigned char offset, 5368c2ecf20Sopenharmony_ci length; 5378c2ecf20Sopenharmony_ci } red, 5388c2ecf20Sopenharmony_ci green, 5398c2ecf20Sopenharmony_ci blue, 5408c2ecf20Sopenharmony_ci transp; 5418c2ecf20Sopenharmony_ci signed char visual; 5428c2ecf20Sopenharmony_ci }; 5438c2ecf20Sopenharmony_ci static const struct RGBT table[]= { 5448c2ecf20Sopenharmony_ci { 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR}, 5458c2ecf20Sopenharmony_ci {15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR}, 5468c2ecf20Sopenharmony_ci {16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR}, 5478c2ecf20Sopenharmony_ci {24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR}, 5488c2ecf20Sopenharmony_ci {32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR} 5498c2ecf20Sopenharmony_ci }; 5508c2ecf20Sopenharmony_ci struct RGBT const *rgbt; 5518c2ecf20Sopenharmony_ci unsigned int bpp = var->bits_per_pixel; 5528c2ecf20Sopenharmony_ci unsigned int vramlen; 5538c2ecf20Sopenharmony_ci unsigned int memlen; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci DBG(__func__) 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci switch (bpp) { 5588c2ecf20Sopenharmony_ci case 4: if (!minfo->capable.cfb4) return -EINVAL; 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci case 8: break; 5618c2ecf20Sopenharmony_ci case 16: break; 5628c2ecf20Sopenharmony_ci case 24: break; 5638c2ecf20Sopenharmony_ci case 32: break; 5648c2ecf20Sopenharmony_ci default: return -EINVAL; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci *ydstorg = 0; 5678c2ecf20Sopenharmony_ci vramlen = minfo->video.len_usable; 5688c2ecf20Sopenharmony_ci if (var->yres_virtual < var->yres) 5698c2ecf20Sopenharmony_ci var->yres_virtual = var->yres; 5708c2ecf20Sopenharmony_ci if (var->xres_virtual < var->xres) 5718c2ecf20Sopenharmony_ci var->xres_virtual = var->xres; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci var->xres_virtual = matroxfb_pitch_adjust(minfo, var->xres_virtual, bpp); 5748c2ecf20Sopenharmony_ci memlen = var->xres_virtual * bpp * var->yres_virtual / 8; 5758c2ecf20Sopenharmony_ci if (memlen > vramlen) { 5768c2ecf20Sopenharmony_ci var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp); 5778c2ecf20Sopenharmony_ci memlen = var->xres_virtual * bpp * var->yres_virtual / 8; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci /* There is hardware bug that no line can cross 4MB boundary */ 5808c2ecf20Sopenharmony_ci /* give up for CFB24, it is impossible to easy workaround it */ 5818c2ecf20Sopenharmony_ci /* for other try to do something */ 5828c2ecf20Sopenharmony_ci if (!minfo->capable.cross4MB && (memlen > 0x400000)) { 5838c2ecf20Sopenharmony_ci if (bpp == 24) { 5848c2ecf20Sopenharmony_ci /* sorry */ 5858c2ecf20Sopenharmony_ci } else { 5868c2ecf20Sopenharmony_ci unsigned int linelen; 5878c2ecf20Sopenharmony_ci unsigned int m1 = linelen = var->xres_virtual * bpp / 8; 5888c2ecf20Sopenharmony_ci unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ 5898c2ecf20Sopenharmony_ci unsigned int max_yres; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci while (m1) { 5928c2ecf20Sopenharmony_ci while (m2 >= m1) m2 -= m1; 5938c2ecf20Sopenharmony_ci swap(m1, m2); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci m2 = linelen * PAGE_SIZE / m2; 5968c2ecf20Sopenharmony_ci *ydstorg = m2 = 0x400000 % m2; 5978c2ecf20Sopenharmony_ci max_yres = (vramlen - m2) / linelen; 5988c2ecf20Sopenharmony_ci if (var->yres_virtual > max_yres) 5998c2ecf20Sopenharmony_ci var->yres_virtual = max_yres; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci /* YDSTLEN contains only signed 16bit value */ 6038c2ecf20Sopenharmony_ci if (var->yres_virtual > 32767) 6048c2ecf20Sopenharmony_ci var->yres_virtual = 32767; 6058c2ecf20Sopenharmony_ci /* we must round yres/xres down, we already rounded y/xres_virtual up 6068c2ecf20Sopenharmony_ci if it was possible. We should return -EINVAL, but I disagree */ 6078c2ecf20Sopenharmony_ci if (var->yres_virtual < var->yres) 6088c2ecf20Sopenharmony_ci var->yres = var->yres_virtual; 6098c2ecf20Sopenharmony_ci if (var->xres_virtual < var->xres) 6108c2ecf20Sopenharmony_ci var->xres = var->xres_virtual; 6118c2ecf20Sopenharmony_ci if (var->xoffset + var->xres > var->xres_virtual) 6128c2ecf20Sopenharmony_ci var->xoffset = var->xres_virtual - var->xres; 6138c2ecf20Sopenharmony_ci if (var->yoffset + var->yres > var->yres_virtual) 6148c2ecf20Sopenharmony_ci var->yoffset = var->yres_virtual - var->yres; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (bpp == 16 && var->green.length == 5) { 6178c2ecf20Sopenharmony_ci bpp--; /* an artificial value - 15 */ 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci for (rgbt = table; rgbt->bpp < bpp; rgbt++); 6218c2ecf20Sopenharmony_ci#define SETCLR(clr)\ 6228c2ecf20Sopenharmony_ci var->clr.offset = rgbt->clr.offset;\ 6238c2ecf20Sopenharmony_ci var->clr.length = rgbt->clr.length 6248c2ecf20Sopenharmony_ci SETCLR(red); 6258c2ecf20Sopenharmony_ci SETCLR(green); 6268c2ecf20Sopenharmony_ci SETCLR(blue); 6278c2ecf20Sopenharmony_ci SETCLR(transp); 6288c2ecf20Sopenharmony_ci#undef SETCLR 6298c2ecf20Sopenharmony_ci *visual = rgbt->visual; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (bpp > 8) 6328c2ecf20Sopenharmony_ci dprintk("matroxfb: truecolor: " 6338c2ecf20Sopenharmony_ci "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", 6348c2ecf20Sopenharmony_ci var->transp.length, var->red.length, var->green.length, var->blue.length, 6358c2ecf20Sopenharmony_ci var->transp.offset, var->red.offset, var->green.offset, var->blue.offset); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci *video_cmap_len = matroxfb_get_cmap_len(var); 6388c2ecf20Sopenharmony_ci dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel, 6398c2ecf20Sopenharmony_ci var->xres_virtual, var->yres_virtual); 6408c2ecf20Sopenharmony_ci return 0; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, 6448c2ecf20Sopenharmony_ci unsigned blue, unsigned transp, 6458c2ecf20Sopenharmony_ci struct fb_info *fb_info) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci DBG(__func__) 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* 6528c2ecf20Sopenharmony_ci * Set a single color register. The values supplied are 6538c2ecf20Sopenharmony_ci * already rounded down to the hardware's capabilities 6548c2ecf20Sopenharmony_ci * (according to the entries in the `var' structure). Return 6558c2ecf20Sopenharmony_ci * != 0 for invalid regno. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (regno >= minfo->curr.cmap_len) 6598c2ecf20Sopenharmony_ci return 1; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (minfo->fbcon.var.grayscale) { 6628c2ecf20Sopenharmony_ci /* gray = 0.30*R + 0.59*G + 0.11*B */ 6638c2ecf20Sopenharmony_ci red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci red = CNVT_TOHW(red, minfo->fbcon.var.red.length); 6678c2ecf20Sopenharmony_ci green = CNVT_TOHW(green, minfo->fbcon.var.green.length); 6688c2ecf20Sopenharmony_ci blue = CNVT_TOHW(blue, minfo->fbcon.var.blue.length); 6698c2ecf20Sopenharmony_ci transp = CNVT_TOHW(transp, minfo->fbcon.var.transp.length); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci switch (minfo->fbcon.var.bits_per_pixel) { 6728c2ecf20Sopenharmony_ci case 4: 6738c2ecf20Sopenharmony_ci case 8: 6748c2ecf20Sopenharmony_ci mga_outb(M_DAC_REG, regno); 6758c2ecf20Sopenharmony_ci mga_outb(M_DAC_VAL, red); 6768c2ecf20Sopenharmony_ci mga_outb(M_DAC_VAL, green); 6778c2ecf20Sopenharmony_ci mga_outb(M_DAC_VAL, blue); 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci case 16: 6808c2ecf20Sopenharmony_ci if (regno >= 16) 6818c2ecf20Sopenharmony_ci break; 6828c2ecf20Sopenharmony_ci { 6838c2ecf20Sopenharmony_ci u_int16_t col = 6848c2ecf20Sopenharmony_ci (red << minfo->fbcon.var.red.offset) | 6858c2ecf20Sopenharmony_ci (green << minfo->fbcon.var.green.offset) | 6868c2ecf20Sopenharmony_ci (blue << minfo->fbcon.var.blue.offset) | 6878c2ecf20Sopenharmony_ci (transp << minfo->fbcon.var.transp.offset); /* for 1:5:5:5 */ 6888c2ecf20Sopenharmony_ci minfo->cmap[regno] = col | (col << 16); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci case 24: 6928c2ecf20Sopenharmony_ci case 32: 6938c2ecf20Sopenharmony_ci if (regno >= 16) 6948c2ecf20Sopenharmony_ci break; 6958c2ecf20Sopenharmony_ci minfo->cmap[regno] = 6968c2ecf20Sopenharmony_ci (red << minfo->fbcon.var.red.offset) | 6978c2ecf20Sopenharmony_ci (green << minfo->fbcon.var.green.offset) | 6988c2ecf20Sopenharmony_ci (blue << minfo->fbcon.var.blue.offset) | 6998c2ecf20Sopenharmony_ci (transp << minfo->fbcon.var.transp.offset); /* 8:8:8:8 */ 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic void matroxfb_init_fix(struct matrox_fb_info *minfo) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci struct fb_fix_screeninfo *fix = &minfo->fbcon.fix; 7088c2ecf20Sopenharmony_ci DBG(__func__) 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci strcpy(fix->id,"MATROX"); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */ 7138c2ecf20Sopenharmony_ci fix->ypanstep = 1; 7148c2ecf20Sopenharmony_ci fix->ywrapstep = 0; 7158c2ecf20Sopenharmony_ci fix->mmio_start = minfo->mmio.base; 7168c2ecf20Sopenharmony_ci fix->mmio_len = minfo->mmio.len; 7178c2ecf20Sopenharmony_ci fix->accel = minfo->devflags.accelerator; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic void matroxfb_update_fix(struct matrox_fb_info *minfo) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct fb_fix_screeninfo *fix = &minfo->fbcon.fix; 7238c2ecf20Sopenharmony_ci DBG(__func__) 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci mutex_lock(&minfo->fbcon.mm_lock); 7268c2ecf20Sopenharmony_ci fix->smem_start = minfo->video.base + minfo->curr.ydstorg.bytes; 7278c2ecf20Sopenharmony_ci fix->smem_len = minfo->video.len_usable - minfo->curr.ydstorg.bytes; 7288c2ecf20Sopenharmony_ci mutex_unlock(&minfo->fbcon.mm_lock); 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci int err; 7348c2ecf20Sopenharmony_ci int visual; 7358c2ecf20Sopenharmony_ci int cmap_len; 7368c2ecf20Sopenharmony_ci unsigned int ydstorg; 7378c2ecf20Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (minfo->dead) { 7408c2ecf20Sopenharmony_ci return -ENXIO; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci if ((err = matroxfb_decode_var(minfo, var, &visual, &cmap_len, &ydstorg)) != 0) 7438c2ecf20Sopenharmony_ci return err; 7448c2ecf20Sopenharmony_ci return 0; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic int matroxfb_set_par(struct fb_info *info) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci int err; 7508c2ecf20Sopenharmony_ci int visual; 7518c2ecf20Sopenharmony_ci int cmap_len; 7528c2ecf20Sopenharmony_ci unsigned int ydstorg; 7538c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var; 7548c2ecf20Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci DBG(__func__) 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (minfo->dead) { 7598c2ecf20Sopenharmony_ci return -ENXIO; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci var = &info->var; 7638c2ecf20Sopenharmony_ci if ((err = matroxfb_decode_var(minfo, var, &visual, &cmap_len, &ydstorg)) != 0) 7648c2ecf20Sopenharmony_ci return err; 7658c2ecf20Sopenharmony_ci minfo->fbcon.screen_base = vaddr_va(minfo->video.vbase) + ydstorg; 7668c2ecf20Sopenharmony_ci matroxfb_update_fix(minfo); 7678c2ecf20Sopenharmony_ci minfo->fbcon.fix.visual = visual; 7688c2ecf20Sopenharmony_ci minfo->fbcon.fix.type = FB_TYPE_PACKED_PIXELS; 7698c2ecf20Sopenharmony_ci minfo->fbcon.fix.type_aux = 0; 7708c2ecf20Sopenharmony_ci minfo->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; 7718c2ecf20Sopenharmony_ci { 7728c2ecf20Sopenharmony_ci unsigned int pos; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci minfo->curr.cmap_len = cmap_len; 7758c2ecf20Sopenharmony_ci ydstorg += minfo->devflags.ydstorg; 7768c2ecf20Sopenharmony_ci minfo->curr.ydstorg.bytes = ydstorg; 7778c2ecf20Sopenharmony_ci minfo->curr.ydstorg.chunks = ydstorg >> (isInterleave(minfo) ? 3 : 2); 7788c2ecf20Sopenharmony_ci if (var->bits_per_pixel == 4) 7798c2ecf20Sopenharmony_ci minfo->curr.ydstorg.pixels = ydstorg; 7808c2ecf20Sopenharmony_ci else 7818c2ecf20Sopenharmony_ci minfo->curr.ydstorg.pixels = (ydstorg * 8) / var->bits_per_pixel; 7828c2ecf20Sopenharmony_ci minfo->curr.final_bppShift = matroxfb_get_final_bppShift(minfo, var->bits_per_pixel); 7838c2ecf20Sopenharmony_ci { struct my_timming mt; 7848c2ecf20Sopenharmony_ci struct matrox_hw_state* hw; 7858c2ecf20Sopenharmony_ci int out; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci matroxfb_var2my(var, &mt); 7888c2ecf20Sopenharmony_ci mt.crtc = MATROXFB_SRC_CRTC1; 7898c2ecf20Sopenharmony_ci /* CRTC1 delays */ 7908c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 7918c2ecf20Sopenharmony_ci case 0: mt.delay = 31 + 0; break; 7928c2ecf20Sopenharmony_ci case 16: mt.delay = 21 + 8; break; 7938c2ecf20Sopenharmony_ci case 24: mt.delay = 17 + 8; break; 7948c2ecf20Sopenharmony_ci case 32: mt.delay = 16 + 8; break; 7958c2ecf20Sopenharmony_ci default: mt.delay = 31 + 8; break; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci hw = &minfo->hw; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci down_read(&minfo->altout.lock); 8018c2ecf20Sopenharmony_ci for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { 8028c2ecf20Sopenharmony_ci if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 && 8038c2ecf20Sopenharmony_ci minfo->outputs[out].output->compute) { 8048c2ecf20Sopenharmony_ci minfo->outputs[out].output->compute(minfo->outputs[out].data, &mt); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci up_read(&minfo->altout.lock); 8088c2ecf20Sopenharmony_ci minfo->crtc1.pixclock = mt.pixclock; 8098c2ecf20Sopenharmony_ci minfo->crtc1.mnp = mt.mnp; 8108c2ecf20Sopenharmony_ci minfo->hw_switch->init(minfo, &mt); 8118c2ecf20Sopenharmony_ci pos = (var->yoffset * var->xres_virtual + var->xoffset) * minfo->curr.final_bppShift / 32; 8128c2ecf20Sopenharmony_ci pos += minfo->curr.ydstorg.chunks; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci hw->CRTC[0x0D] = pos & 0xFF; 8158c2ecf20Sopenharmony_ci hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; 8168c2ecf20Sopenharmony_ci hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); 8178c2ecf20Sopenharmony_ci hw->CRTCEXT[8] = pos >> 21; 8188c2ecf20Sopenharmony_ci minfo->hw_switch->restore(minfo); 8198c2ecf20Sopenharmony_ci update_crtc2(minfo, pos); 8208c2ecf20Sopenharmony_ci down_read(&minfo->altout.lock); 8218c2ecf20Sopenharmony_ci for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { 8228c2ecf20Sopenharmony_ci if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 && 8238c2ecf20Sopenharmony_ci minfo->outputs[out].output->program) { 8248c2ecf20Sopenharmony_ci minfo->outputs[out].output->program(minfo->outputs[out].data); 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { 8288c2ecf20Sopenharmony_ci if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 && 8298c2ecf20Sopenharmony_ci minfo->outputs[out].output->start) { 8308c2ecf20Sopenharmony_ci minfo->outputs[out].output->start(minfo->outputs[out].data); 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci up_read(&minfo->altout.lock); 8348c2ecf20Sopenharmony_ci matrox_cfbX_init(minfo); 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci minfo->initialized = 1; 8388c2ecf20Sopenharmony_ci return 0; 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic int matroxfb_get_vblank(struct matrox_fb_info *minfo, 8428c2ecf20Sopenharmony_ci struct fb_vblank *vblank) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci unsigned int sts1; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci matroxfb_enable_irq(minfo, 0); 8478c2ecf20Sopenharmony_ci memset(vblank, 0, sizeof(*vblank)); 8488c2ecf20Sopenharmony_ci vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC | 8498c2ecf20Sopenharmony_ci FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK; 8508c2ecf20Sopenharmony_ci sts1 = mga_inb(M_INSTS1); 8518c2ecf20Sopenharmony_ci vblank->vcount = mga_inl(M_VCOUNT); 8528c2ecf20Sopenharmony_ci /* BTW, on my PIII/450 with G400, reading M_INSTS1 8538c2ecf20Sopenharmony_ci byte makes this call about 12% slower (1.70 vs. 2.05 us 8548c2ecf20Sopenharmony_ci per ioctl()) */ 8558c2ecf20Sopenharmony_ci if (sts1 & 1) 8568c2ecf20Sopenharmony_ci vblank->flags |= FB_VBLANK_HBLANKING; 8578c2ecf20Sopenharmony_ci if (sts1 & 8) 8588c2ecf20Sopenharmony_ci vblank->flags |= FB_VBLANK_VSYNCING; 8598c2ecf20Sopenharmony_ci if (vblank->vcount >= minfo->fbcon.var.yres) 8608c2ecf20Sopenharmony_ci vblank->flags |= FB_VBLANK_VBLANKING; 8618c2ecf20Sopenharmony_ci if (test_bit(0, &minfo->irq_flags)) { 8628c2ecf20Sopenharmony_ci vblank->flags |= FB_VBLANK_HAVE_COUNT; 8638c2ecf20Sopenharmony_ci /* Only one writer, aligned int value... 8648c2ecf20Sopenharmony_ci it should work without lock and without atomic_t */ 8658c2ecf20Sopenharmony_ci vblank->count = minfo->crtc1.vsync.cnt; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci return 0; 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic struct matrox_altout panellink_output = { 8718c2ecf20Sopenharmony_ci .name = "Panellink output", 8728c2ecf20Sopenharmony_ci}; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic int matroxfb_ioctl(struct fb_info *info, 8758c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 8788c2ecf20Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci DBG(__func__) 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (minfo->dead) { 8838c2ecf20Sopenharmony_ci return -ENXIO; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci switch (cmd) { 8878c2ecf20Sopenharmony_ci case FBIOGET_VBLANK: 8888c2ecf20Sopenharmony_ci { 8898c2ecf20Sopenharmony_ci struct fb_vblank vblank; 8908c2ecf20Sopenharmony_ci int err; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci err = matroxfb_get_vblank(minfo, &vblank); 8938c2ecf20Sopenharmony_ci if (err) 8948c2ecf20Sopenharmony_ci return err; 8958c2ecf20Sopenharmony_ci if (copy_to_user(argp, &vblank, sizeof(vblank))) 8968c2ecf20Sopenharmony_ci return -EFAULT; 8978c2ecf20Sopenharmony_ci return 0; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci case FBIO_WAITFORVSYNC: 9008c2ecf20Sopenharmony_ci { 9018c2ecf20Sopenharmony_ci u_int32_t crt; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (get_user(crt, (u_int32_t __user *)arg)) 9048c2ecf20Sopenharmony_ci return -EFAULT; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci return matroxfb_wait_for_sync(minfo, crt); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci case MATROXFB_SET_OUTPUT_MODE: 9098c2ecf20Sopenharmony_ci { 9108c2ecf20Sopenharmony_ci struct matroxioc_output_mode mom; 9118c2ecf20Sopenharmony_ci struct matrox_altout *oproc; 9128c2ecf20Sopenharmony_ci int val; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (copy_from_user(&mom, argp, sizeof(mom))) 9158c2ecf20Sopenharmony_ci return -EFAULT; 9168c2ecf20Sopenharmony_ci if (mom.output >= MATROXFB_MAX_OUTPUTS) 9178c2ecf20Sopenharmony_ci return -ENXIO; 9188c2ecf20Sopenharmony_ci down_read(&minfo->altout.lock); 9198c2ecf20Sopenharmony_ci oproc = minfo->outputs[mom.output].output; 9208c2ecf20Sopenharmony_ci if (!oproc) { 9218c2ecf20Sopenharmony_ci val = -ENXIO; 9228c2ecf20Sopenharmony_ci } else if (!oproc->verifymode) { 9238c2ecf20Sopenharmony_ci if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) { 9248c2ecf20Sopenharmony_ci val = 0; 9258c2ecf20Sopenharmony_ci } else { 9268c2ecf20Sopenharmony_ci val = -EINVAL; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci } else { 9298c2ecf20Sopenharmony_ci val = oproc->verifymode(minfo->outputs[mom.output].data, mom.mode); 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci if (!val) { 9328c2ecf20Sopenharmony_ci if (minfo->outputs[mom.output].mode != mom.mode) { 9338c2ecf20Sopenharmony_ci minfo->outputs[mom.output].mode = mom.mode; 9348c2ecf20Sopenharmony_ci val = 1; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci up_read(&minfo->altout.lock); 9388c2ecf20Sopenharmony_ci if (val != 1) 9398c2ecf20Sopenharmony_ci return val; 9408c2ecf20Sopenharmony_ci switch (minfo->outputs[mom.output].src) { 9418c2ecf20Sopenharmony_ci case MATROXFB_SRC_CRTC1: 9428c2ecf20Sopenharmony_ci matroxfb_set_par(info); 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci case MATROXFB_SRC_CRTC2: 9458c2ecf20Sopenharmony_ci { 9468c2ecf20Sopenharmony_ci struct matroxfb_dh_fb_info* crtc2; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci down_read(&minfo->crtc2.lock); 9498c2ecf20Sopenharmony_ci crtc2 = minfo->crtc2.info; 9508c2ecf20Sopenharmony_ci if (crtc2) 9518c2ecf20Sopenharmony_ci crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon); 9528c2ecf20Sopenharmony_ci up_read(&minfo->crtc2.lock); 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci break; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci case MATROXFB_GET_OUTPUT_MODE: 9598c2ecf20Sopenharmony_ci { 9608c2ecf20Sopenharmony_ci struct matroxioc_output_mode mom; 9618c2ecf20Sopenharmony_ci struct matrox_altout *oproc; 9628c2ecf20Sopenharmony_ci int val; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (copy_from_user(&mom, argp, sizeof(mom))) 9658c2ecf20Sopenharmony_ci return -EFAULT; 9668c2ecf20Sopenharmony_ci if (mom.output >= MATROXFB_MAX_OUTPUTS) 9678c2ecf20Sopenharmony_ci return -ENXIO; 9688c2ecf20Sopenharmony_ci down_read(&minfo->altout.lock); 9698c2ecf20Sopenharmony_ci oproc = minfo->outputs[mom.output].output; 9708c2ecf20Sopenharmony_ci if (!oproc) { 9718c2ecf20Sopenharmony_ci val = -ENXIO; 9728c2ecf20Sopenharmony_ci } else { 9738c2ecf20Sopenharmony_ci mom.mode = minfo->outputs[mom.output].mode; 9748c2ecf20Sopenharmony_ci val = 0; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci up_read(&minfo->altout.lock); 9778c2ecf20Sopenharmony_ci if (val) 9788c2ecf20Sopenharmony_ci return val; 9798c2ecf20Sopenharmony_ci if (copy_to_user(argp, &mom, sizeof(mom))) 9808c2ecf20Sopenharmony_ci return -EFAULT; 9818c2ecf20Sopenharmony_ci return 0; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci case MATROXFB_SET_OUTPUT_CONNECTION: 9848c2ecf20Sopenharmony_ci { 9858c2ecf20Sopenharmony_ci u_int32_t tmp; 9868c2ecf20Sopenharmony_ci int i; 9878c2ecf20Sopenharmony_ci int changes; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, argp, sizeof(tmp))) 9908c2ecf20Sopenharmony_ci return -EFAULT; 9918c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 9928c2ecf20Sopenharmony_ci if (tmp & (1 << i)) { 9938c2ecf20Sopenharmony_ci if (i >= MATROXFB_MAX_OUTPUTS) 9948c2ecf20Sopenharmony_ci return -ENXIO; 9958c2ecf20Sopenharmony_ci if (!minfo->outputs[i].output) 9968c2ecf20Sopenharmony_ci return -ENXIO; 9978c2ecf20Sopenharmony_ci switch (minfo->outputs[i].src) { 9988c2ecf20Sopenharmony_ci case MATROXFB_SRC_NONE: 9998c2ecf20Sopenharmony_ci case MATROXFB_SRC_CRTC1: 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci default: 10028c2ecf20Sopenharmony_ci return -EBUSY; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci if (minfo->devflags.panellink) { 10078c2ecf20Sopenharmony_ci if (tmp & MATROXFB_OUTPUT_CONN_DFP) { 10088c2ecf20Sopenharmony_ci if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY) 10098c2ecf20Sopenharmony_ci return -EINVAL; 10108c2ecf20Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 10118c2ecf20Sopenharmony_ci if (minfo->outputs[i].src == MATROXFB_SRC_CRTC2) { 10128c2ecf20Sopenharmony_ci return -EBUSY; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci changes = 0; 10188c2ecf20Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 10198c2ecf20Sopenharmony_ci if (tmp & (1 << i)) { 10208c2ecf20Sopenharmony_ci if (minfo->outputs[i].src != MATROXFB_SRC_CRTC1) { 10218c2ecf20Sopenharmony_ci changes = 1; 10228c2ecf20Sopenharmony_ci minfo->outputs[i].src = MATROXFB_SRC_CRTC1; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci } else if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) { 10258c2ecf20Sopenharmony_ci changes = 1; 10268c2ecf20Sopenharmony_ci minfo->outputs[i].src = MATROXFB_SRC_NONE; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci if (!changes) 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci matroxfb_set_par(info); 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci case MATROXFB_GET_OUTPUT_CONNECTION: 10358c2ecf20Sopenharmony_ci { 10368c2ecf20Sopenharmony_ci u_int32_t conn = 0; 10378c2ecf20Sopenharmony_ci int i; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 10408c2ecf20Sopenharmony_ci if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) { 10418c2ecf20Sopenharmony_ci conn |= 1 << i; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci if (put_user(conn, (u_int32_t __user *)arg)) 10458c2ecf20Sopenharmony_ci return -EFAULT; 10468c2ecf20Sopenharmony_ci return 0; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci case MATROXFB_GET_AVAILABLE_OUTPUTS: 10498c2ecf20Sopenharmony_ci { 10508c2ecf20Sopenharmony_ci u_int32_t conn = 0; 10518c2ecf20Sopenharmony_ci int i; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 10548c2ecf20Sopenharmony_ci if (minfo->outputs[i].output) { 10558c2ecf20Sopenharmony_ci switch (minfo->outputs[i].src) { 10568c2ecf20Sopenharmony_ci case MATROXFB_SRC_NONE: 10578c2ecf20Sopenharmony_ci case MATROXFB_SRC_CRTC1: 10588c2ecf20Sopenharmony_ci conn |= 1 << i; 10598c2ecf20Sopenharmony_ci break; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci if (minfo->devflags.panellink) { 10648c2ecf20Sopenharmony_ci if (conn & MATROXFB_OUTPUT_CONN_DFP) 10658c2ecf20Sopenharmony_ci conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY; 10668c2ecf20Sopenharmony_ci if (conn & MATROXFB_OUTPUT_CONN_SECONDARY) 10678c2ecf20Sopenharmony_ci conn &= ~MATROXFB_OUTPUT_CONN_DFP; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci if (put_user(conn, (u_int32_t __user *)arg)) 10708c2ecf20Sopenharmony_ci return -EFAULT; 10718c2ecf20Sopenharmony_ci return 0; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci case MATROXFB_GET_ALL_OUTPUTS: 10748c2ecf20Sopenharmony_ci { 10758c2ecf20Sopenharmony_ci u_int32_t conn = 0; 10768c2ecf20Sopenharmony_ci int i; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 10798c2ecf20Sopenharmony_ci if (minfo->outputs[i].output) { 10808c2ecf20Sopenharmony_ci conn |= 1 << i; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci if (put_user(conn, (u_int32_t __user *)arg)) 10848c2ecf20Sopenharmony_ci return -EFAULT; 10858c2ecf20Sopenharmony_ci return 0; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci case VIDIOC_QUERYCAP: 10888c2ecf20Sopenharmony_ci { 10898c2ecf20Sopenharmony_ci struct v4l2_capability r; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci memset(&r, 0, sizeof(r)); 10928c2ecf20Sopenharmony_ci strcpy(r.driver, "matroxfb"); 10938c2ecf20Sopenharmony_ci strcpy(r.card, "Matrox"); 10948c2ecf20Sopenharmony_ci sprintf(r.bus_info, "PCI:%s", pci_name(minfo->pcidev)); 10958c2ecf20Sopenharmony_ci r.version = KERNEL_VERSION(1,0,0); 10968c2ecf20Sopenharmony_ci r.capabilities = V4L2_CAP_VIDEO_OUTPUT; 10978c2ecf20Sopenharmony_ci if (copy_to_user(argp, &r, sizeof(r))) 10988c2ecf20Sopenharmony_ci return -EFAULT; 10998c2ecf20Sopenharmony_ci return 0; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci case VIDIOC_QUERYCTRL: 11038c2ecf20Sopenharmony_ci { 11048c2ecf20Sopenharmony_ci struct v4l2_queryctrl qctrl; 11058c2ecf20Sopenharmony_ci int err; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (copy_from_user(&qctrl, argp, sizeof(qctrl))) 11088c2ecf20Sopenharmony_ci return -EFAULT; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci down_read(&minfo->altout.lock); 11118c2ecf20Sopenharmony_ci if (!minfo->outputs[1].output) { 11128c2ecf20Sopenharmony_ci err = -ENXIO; 11138c2ecf20Sopenharmony_ci } else if (minfo->outputs[1].output->getqueryctrl) { 11148c2ecf20Sopenharmony_ci err = minfo->outputs[1].output->getqueryctrl(minfo->outputs[1].data, &qctrl); 11158c2ecf20Sopenharmony_ci } else { 11168c2ecf20Sopenharmony_ci err = -EINVAL; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci up_read(&minfo->altout.lock); 11198c2ecf20Sopenharmony_ci if (err >= 0 && 11208c2ecf20Sopenharmony_ci copy_to_user(argp, &qctrl, sizeof(qctrl))) 11218c2ecf20Sopenharmony_ci return -EFAULT; 11228c2ecf20Sopenharmony_ci return err; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci case VIDIOC_G_CTRL: 11258c2ecf20Sopenharmony_ci { 11268c2ecf20Sopenharmony_ci struct v4l2_control ctrl; 11278c2ecf20Sopenharmony_ci int err; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (copy_from_user(&ctrl, argp, sizeof(ctrl))) 11308c2ecf20Sopenharmony_ci return -EFAULT; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci down_read(&minfo->altout.lock); 11338c2ecf20Sopenharmony_ci if (!minfo->outputs[1].output) { 11348c2ecf20Sopenharmony_ci err = -ENXIO; 11358c2ecf20Sopenharmony_ci } else if (minfo->outputs[1].output->getctrl) { 11368c2ecf20Sopenharmony_ci err = minfo->outputs[1].output->getctrl(minfo->outputs[1].data, &ctrl); 11378c2ecf20Sopenharmony_ci } else { 11388c2ecf20Sopenharmony_ci err = -EINVAL; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci up_read(&minfo->altout.lock); 11418c2ecf20Sopenharmony_ci if (err >= 0 && 11428c2ecf20Sopenharmony_ci copy_to_user(argp, &ctrl, sizeof(ctrl))) 11438c2ecf20Sopenharmony_ci return -EFAULT; 11448c2ecf20Sopenharmony_ci return err; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci case VIDIOC_S_CTRL: 11478c2ecf20Sopenharmony_ci { 11488c2ecf20Sopenharmony_ci struct v4l2_control ctrl; 11498c2ecf20Sopenharmony_ci int err; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (copy_from_user(&ctrl, argp, sizeof(ctrl))) 11528c2ecf20Sopenharmony_ci return -EFAULT; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci down_read(&minfo->altout.lock); 11558c2ecf20Sopenharmony_ci if (!minfo->outputs[1].output) { 11568c2ecf20Sopenharmony_ci err = -ENXIO; 11578c2ecf20Sopenharmony_ci } else if (minfo->outputs[1].output->setctrl) { 11588c2ecf20Sopenharmony_ci err = minfo->outputs[1].output->setctrl(minfo->outputs[1].data, &ctrl); 11598c2ecf20Sopenharmony_ci } else { 11608c2ecf20Sopenharmony_ci err = -EINVAL; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci up_read(&minfo->altout.lock); 11638c2ecf20Sopenharmony_ci return err; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci return -ENOTTY; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cistatic int matroxfb_blank(int blank, struct fb_info *info) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci int seq; 11748c2ecf20Sopenharmony_ci int crtc; 11758c2ecf20Sopenharmony_ci CRITFLAGS 11768c2ecf20Sopenharmony_ci struct matrox_fb_info *minfo = info2minfo(info); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci DBG(__func__) 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (minfo->dead) 11818c2ecf20Sopenharmony_ci return 1; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci switch (blank) { 11848c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: seq = 0x20; crtc = 0x00; break; /* works ??? */ 11858c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: seq = 0x20; crtc = 0x10; break; 11868c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: seq = 0x20; crtc = 0x20; break; 11878c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: seq = 0x20; crtc = 0x30; break; 11888c2ecf20Sopenharmony_ci default: seq = 0x00; crtc = 0x00; break; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci CRITBEGIN 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci mga_outb(M_SEQ_INDEX, 1); 11948c2ecf20Sopenharmony_ci mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq); 11958c2ecf20Sopenharmony_ci mga_outb(M_EXTVGA_INDEX, 1); 11968c2ecf20Sopenharmony_ci mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci CRITEND 11998c2ecf20Sopenharmony_ci return 0; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic const struct fb_ops matroxfb_ops = { 12038c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12048c2ecf20Sopenharmony_ci .fb_open = matroxfb_open, 12058c2ecf20Sopenharmony_ci .fb_release = matroxfb_release, 12068c2ecf20Sopenharmony_ci .fb_check_var = matroxfb_check_var, 12078c2ecf20Sopenharmony_ci .fb_set_par = matroxfb_set_par, 12088c2ecf20Sopenharmony_ci .fb_setcolreg = matroxfb_setcolreg, 12098c2ecf20Sopenharmony_ci .fb_pan_display =matroxfb_pan_display, 12108c2ecf20Sopenharmony_ci .fb_blank = matroxfb_blank, 12118c2ecf20Sopenharmony_ci .fb_ioctl = matroxfb_ioctl, 12128c2ecf20Sopenharmony_ci/* .fb_fillrect = <set by matrox_cfbX_init>, */ 12138c2ecf20Sopenharmony_ci/* .fb_copyarea = <set by matrox_cfbX_init>, */ 12148c2ecf20Sopenharmony_ci/* .fb_imageblit = <set by matrox_cfbX_init>, */ 12158c2ecf20Sopenharmony_ci/* .fb_cursor = <set by matrox_cfbX_init>, */ 12168c2ecf20Sopenharmony_ci}; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci#define RSDepth(X) (((X) >> 8) & 0x0F) 12198c2ecf20Sopenharmony_ci#define RS8bpp 0x1 12208c2ecf20Sopenharmony_ci#define RS15bpp 0x2 12218c2ecf20Sopenharmony_ci#define RS16bpp 0x3 12228c2ecf20Sopenharmony_ci#define RS32bpp 0x4 12238c2ecf20Sopenharmony_ci#define RS4bpp 0x5 12248c2ecf20Sopenharmony_ci#define RS24bpp 0x6 12258c2ecf20Sopenharmony_ci#define RSText 0x7 12268c2ecf20Sopenharmony_ci#define RSText8 0x8 12278c2ecf20Sopenharmony_ci/* 9-F */ 12288c2ecf20Sopenharmony_cistatic struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = { 12298c2ecf20Sopenharmony_ci { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 }, 12308c2ecf20Sopenharmony_ci { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 }, 12318c2ecf20Sopenharmony_ci { { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 }, 12328c2ecf20Sopenharmony_ci { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 }, 12338c2ecf20Sopenharmony_ci { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 }, 12348c2ecf20Sopenharmony_ci { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 }, 12358c2ecf20Sopenharmony_ci { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */ 12368c2ecf20Sopenharmony_ci { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */ 12378c2ecf20Sopenharmony_ci}; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ 12408c2ecf20Sopenharmony_cistatic unsigned int mem; /* "matroxfb:mem:xxxxxM" */ 12418c2ecf20Sopenharmony_cistatic int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ 12428c2ecf20Sopenharmony_cistatic int inv24; /* "matroxfb:inv24" */ 12438c2ecf20Sopenharmony_cistatic int cross4MB = -1; /* "matroxfb:cross4MB" */ 12448c2ecf20Sopenharmony_cistatic int disabled; /* "matroxfb:disabled" */ 12458c2ecf20Sopenharmony_cistatic int noaccel; /* "matroxfb:noaccel" */ 12468c2ecf20Sopenharmony_cistatic int nopan; /* "matroxfb:nopan" */ 12478c2ecf20Sopenharmony_cistatic int no_pci_retry; /* "matroxfb:nopciretry" */ 12488c2ecf20Sopenharmony_cistatic int novga; /* "matroxfb:novga" */ 12498c2ecf20Sopenharmony_cistatic int nobios; /* "matroxfb:nobios" */ 12508c2ecf20Sopenharmony_cistatic int noinit = 1; /* "matroxfb:init" */ 12518c2ecf20Sopenharmony_cistatic int inverse; /* "matroxfb:inverse" */ 12528c2ecf20Sopenharmony_cistatic int sgram; /* "matroxfb:sgram" */ 12538c2ecf20Sopenharmony_cistatic int mtrr = 1; /* "matroxfb:nomtrr" */ 12548c2ecf20Sopenharmony_cistatic int grayscale; /* "matroxfb:grayscale" */ 12558c2ecf20Sopenharmony_cistatic int dev = -1; /* "matroxfb:dev:xxxxx" */ 12568c2ecf20Sopenharmony_cistatic unsigned int vesa = ~0; /* "matroxfb:vesa:xxxxx" */ 12578c2ecf20Sopenharmony_cistatic int depth = -1; /* "matroxfb:depth:xxxxx" */ 12588c2ecf20Sopenharmony_cistatic unsigned int xres; /* "matroxfb:xres:xxxxx" */ 12598c2ecf20Sopenharmony_cistatic unsigned int yres; /* "matroxfb:yres:xxxxx" */ 12608c2ecf20Sopenharmony_cistatic unsigned int upper = ~0; /* "matroxfb:upper:xxxxx" */ 12618c2ecf20Sopenharmony_cistatic unsigned int lower = ~0; /* "matroxfb:lower:xxxxx" */ 12628c2ecf20Sopenharmony_cistatic unsigned int vslen; /* "matroxfb:vslen:xxxxx" */ 12638c2ecf20Sopenharmony_cistatic unsigned int left = ~0; /* "matroxfb:left:xxxxx" */ 12648c2ecf20Sopenharmony_cistatic unsigned int right = ~0; /* "matroxfb:right:xxxxx" */ 12658c2ecf20Sopenharmony_cistatic unsigned int hslen; /* "matroxfb:hslen:xxxxx" */ 12668c2ecf20Sopenharmony_cistatic unsigned int pixclock; /* "matroxfb:pixclock:xxxxx" */ 12678c2ecf20Sopenharmony_cistatic int sync = -1; /* "matroxfb:sync:xxxxx" */ 12688c2ecf20Sopenharmony_cistatic unsigned int fv; /* "matroxfb:fv:xxxxx" */ 12698c2ecf20Sopenharmony_cistatic unsigned int fh; /* "matroxfb:fh:xxxxxk" */ 12708c2ecf20Sopenharmony_cistatic unsigned int maxclk; /* "matroxfb:maxclk:xxxxM" */ 12718c2ecf20Sopenharmony_cistatic int dfp; /* "matroxfb:dfp */ 12728c2ecf20Sopenharmony_cistatic int dfp_type = -1; /* "matroxfb:dfp:xxx */ 12738c2ecf20Sopenharmony_cistatic int memtype = -1; /* "matroxfb:memtype:xxx" */ 12748c2ecf20Sopenharmony_cistatic char outputs[8]; /* "matroxfb:outputs:xxx" */ 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci#ifndef MODULE 12778c2ecf20Sopenharmony_cistatic char videomode[64]; /* "matroxfb:mode:xxxxx" or "matroxfb:xxxxx" */ 12788c2ecf20Sopenharmony_ci#endif 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic int matroxfb_getmemory(struct matrox_fb_info *minfo, 12818c2ecf20Sopenharmony_ci unsigned int maxSize, unsigned int *realSize) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci vaddr_t vm; 12848c2ecf20Sopenharmony_ci unsigned int offs; 12858c2ecf20Sopenharmony_ci unsigned int offs2; 12868c2ecf20Sopenharmony_ci unsigned char orig; 12878c2ecf20Sopenharmony_ci unsigned char bytes[32]; 12888c2ecf20Sopenharmony_ci unsigned char* tmp; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci DBG(__func__) 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci vm = minfo->video.vbase; 12938c2ecf20Sopenharmony_ci maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ 12948c2ecf20Sopenharmony_ci /* at least 2MB */ 12958c2ecf20Sopenharmony_ci if (maxSize < 0x0200000) return 0; 12968c2ecf20Sopenharmony_ci if (maxSize > 0x2000000) maxSize = 0x2000000; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci mga_outb(M_EXTVGA_INDEX, 0x03); 12998c2ecf20Sopenharmony_ci orig = mga_inb(M_EXTVGA_DATA); 13008c2ecf20Sopenharmony_ci mga_outb(M_EXTVGA_DATA, orig | 0x80); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci tmp = bytes; 13038c2ecf20Sopenharmony_ci for (offs = 0x100000; offs < maxSize; offs += 0x200000) 13048c2ecf20Sopenharmony_ci *tmp++ = mga_readb(vm, offs); 13058c2ecf20Sopenharmony_ci for (offs = 0x100000; offs < maxSize; offs += 0x200000) 13068c2ecf20Sopenharmony_ci mga_writeb(vm, offs, 0x02); 13078c2ecf20Sopenharmony_ci mga_outb(M_CACHEFLUSH, 0x00); 13088c2ecf20Sopenharmony_ci for (offs = 0x100000; offs < maxSize; offs += 0x200000) { 13098c2ecf20Sopenharmony_ci if (mga_readb(vm, offs) != 0x02) 13108c2ecf20Sopenharmony_ci break; 13118c2ecf20Sopenharmony_ci mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02); 13128c2ecf20Sopenharmony_ci if (mga_readb(vm, offs)) 13138c2ecf20Sopenharmony_ci break; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci tmp = bytes; 13168c2ecf20Sopenharmony_ci for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000) 13178c2ecf20Sopenharmony_ci mga_writeb(vm, offs2, *tmp++); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci mga_outb(M_EXTVGA_INDEX, 0x03); 13208c2ecf20Sopenharmony_ci mga_outb(M_EXTVGA_DATA, orig); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci *realSize = offs - 0x100000; 13238c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM 13248c2ecf20Sopenharmony_ci minfo->interleave = !(!isMillenium(minfo) || ((offs - 0x100000) & 0x3FFFFF)); 13258c2ecf20Sopenharmony_ci#endif 13268c2ecf20Sopenharmony_ci return 1; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistruct video_board { 13308c2ecf20Sopenharmony_ci int maxvram; 13318c2ecf20Sopenharmony_ci int maxdisplayable; 13328c2ecf20Sopenharmony_ci int accelID; 13338c2ecf20Sopenharmony_ci struct matrox_switch* lowlevel; 13348c2ecf20Sopenharmony_ci }; 13358c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM 13368c2ecf20Sopenharmony_cistatic struct video_board vbMillennium = { 13378c2ecf20Sopenharmony_ci .maxvram = 0x0800000, 13388c2ecf20Sopenharmony_ci .maxdisplayable = 0x0800000, 13398c2ecf20Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGA2064W, 13408c2ecf20Sopenharmony_ci .lowlevel = &matrox_millennium 13418c2ecf20Sopenharmony_ci}; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic struct video_board vbMillennium2 = { 13448c2ecf20Sopenharmony_ci .maxvram = 0x1000000, 13458c2ecf20Sopenharmony_ci .maxdisplayable = 0x0800000, 13468c2ecf20Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGA2164W, 13478c2ecf20Sopenharmony_ci .lowlevel = &matrox_millennium 13488c2ecf20Sopenharmony_ci}; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic struct video_board vbMillennium2A = { 13518c2ecf20Sopenharmony_ci .maxvram = 0x1000000, 13528c2ecf20Sopenharmony_ci .maxdisplayable = 0x0800000, 13538c2ecf20Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGA2164W_AGP, 13548c2ecf20Sopenharmony_ci .lowlevel = &matrox_millennium 13558c2ecf20Sopenharmony_ci}; 13568c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_MATROX_MILLENIUM */ 13578c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MYSTIQUE 13588c2ecf20Sopenharmony_cistatic struct video_board vbMystique = { 13598c2ecf20Sopenharmony_ci .maxvram = 0x0800000, 13608c2ecf20Sopenharmony_ci .maxdisplayable = 0x0800000, 13618c2ecf20Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGA1064SG, 13628c2ecf20Sopenharmony_ci .lowlevel = &matrox_mystique 13638c2ecf20Sopenharmony_ci}; 13648c2ecf20Sopenharmony_ci#endif /* CONFIG_FB_MATROX_MYSTIQUE */ 13658c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_G 13668c2ecf20Sopenharmony_cistatic struct video_board vbG100 = { 13678c2ecf20Sopenharmony_ci .maxvram = 0x0800000, 13688c2ecf20Sopenharmony_ci .maxdisplayable = 0x0800000, 13698c2ecf20Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGAG100, 13708c2ecf20Sopenharmony_ci .lowlevel = &matrox_G100 13718c2ecf20Sopenharmony_ci}; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic struct video_board vbG200 = { 13748c2ecf20Sopenharmony_ci .maxvram = 0x1000000, 13758c2ecf20Sopenharmony_ci .maxdisplayable = 0x1000000, 13768c2ecf20Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGAG200, 13778c2ecf20Sopenharmony_ci .lowlevel = &matrox_G100 13788c2ecf20Sopenharmony_ci}; 13798c2ecf20Sopenharmony_cistatic struct video_board vbG200eW = { 13808c2ecf20Sopenharmony_ci .maxvram = 0x1000000, 13818c2ecf20Sopenharmony_ci .maxdisplayable = 0x0800000, 13828c2ecf20Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGAG200, 13838c2ecf20Sopenharmony_ci .lowlevel = &matrox_G100 13848c2ecf20Sopenharmony_ci}; 13858c2ecf20Sopenharmony_ci/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for 13868c2ecf20Sopenharmony_ci whole 32MB */ 13878c2ecf20Sopenharmony_cistatic struct video_board vbG400 = { 13888c2ecf20Sopenharmony_ci .maxvram = 0x2000000, 13898c2ecf20Sopenharmony_ci .maxdisplayable = 0x1000000, 13908c2ecf20Sopenharmony_ci .accelID = FB_ACCEL_MATROX_MGAG400, 13918c2ecf20Sopenharmony_ci .lowlevel = &matrox_G100 13928c2ecf20Sopenharmony_ci}; 13938c2ecf20Sopenharmony_ci#endif 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci#define DEVF_VIDEO64BIT 0x0001 13968c2ecf20Sopenharmony_ci#define DEVF_SWAPS 0x0002 13978c2ecf20Sopenharmony_ci#define DEVF_SRCORG 0x0004 13988c2ecf20Sopenharmony_ci#define DEVF_DUALHEAD 0x0008 13998c2ecf20Sopenharmony_ci#define DEVF_CROSS4MB 0x0010 14008c2ecf20Sopenharmony_ci#define DEVF_TEXT4B 0x0020 14018c2ecf20Sopenharmony_ci/* #define DEVF_recycled 0x0040 */ 14028c2ecf20Sopenharmony_ci/* #define DEVF_recycled 0x0080 */ 14038c2ecf20Sopenharmony_ci#define DEVF_SUPPORT32MB 0x0100 14048c2ecf20Sopenharmony_ci#define DEVF_ANY_VXRES 0x0200 14058c2ecf20Sopenharmony_ci#define DEVF_TEXT16B 0x0400 14068c2ecf20Sopenharmony_ci#define DEVF_CRTC2 0x0800 14078c2ecf20Sopenharmony_ci#define DEVF_MAVEN_CAPABLE 0x1000 14088c2ecf20Sopenharmony_ci#define DEVF_PANELLINK_CAPABLE 0x2000 14098c2ecf20Sopenharmony_ci#define DEVF_G450DAC 0x4000 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB) 14128c2ecf20Sopenharmony_ci#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD) 14138c2ecf20Sopenharmony_ci#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */ 14148c2ecf20Sopenharmony_ci#define DEVF_G200 (DEVF_G2CORE) 14158c2ecf20Sopenharmony_ci#define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2) 14168c2ecf20Sopenharmony_ci/* if you'll find how to drive DFP... */ 14178c2ecf20Sopenharmony_ci#define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD) 14188c2ecf20Sopenharmony_ci#define DEVF_G550 (DEVF_G450) 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic struct board { 14218c2ecf20Sopenharmony_ci unsigned short vendor, device, rev, svid, sid; 14228c2ecf20Sopenharmony_ci unsigned int flags; 14238c2ecf20Sopenharmony_ci unsigned int maxclk; 14248c2ecf20Sopenharmony_ci enum mga_chip chip; 14258c2ecf20Sopenharmony_ci struct video_board* base; 14268c2ecf20Sopenharmony_ci const char* name; 14278c2ecf20Sopenharmony_ci } dev_list[] = { 14288c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM 14298c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF, 14308c2ecf20Sopenharmony_ci 0, 0, 14318c2ecf20Sopenharmony_ci DEVF_TEXT4B, 14328c2ecf20Sopenharmony_ci 230000, 14338c2ecf20Sopenharmony_ci MGA_2064, 14348c2ecf20Sopenharmony_ci &vbMillennium, 14358c2ecf20Sopenharmony_ci "Millennium (PCI)"}, 14368c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF, 14378c2ecf20Sopenharmony_ci 0, 0, 14388c2ecf20Sopenharmony_ci DEVF_SWAPS, 14398c2ecf20Sopenharmony_ci 220000, 14408c2ecf20Sopenharmony_ci MGA_2164, 14418c2ecf20Sopenharmony_ci &vbMillennium2, 14428c2ecf20Sopenharmony_ci "Millennium II (PCI)"}, 14438c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF, 14448c2ecf20Sopenharmony_ci 0, 0, 14458c2ecf20Sopenharmony_ci DEVF_SWAPS, 14468c2ecf20Sopenharmony_ci 250000, 14478c2ecf20Sopenharmony_ci MGA_2164, 14488c2ecf20Sopenharmony_ci &vbMillennium2A, 14498c2ecf20Sopenharmony_ci "Millennium II (AGP)"}, 14508c2ecf20Sopenharmony_ci#endif 14518c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MYSTIQUE 14528c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02, 14538c2ecf20Sopenharmony_ci 0, 0, 14548c2ecf20Sopenharmony_ci DEVF_VIDEO64BIT | DEVF_CROSS4MB, 14558c2ecf20Sopenharmony_ci 180000, 14568c2ecf20Sopenharmony_ci MGA_1064, 14578c2ecf20Sopenharmony_ci &vbMystique, 14588c2ecf20Sopenharmony_ci "Mystique (PCI)"}, 14598c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF, 14608c2ecf20Sopenharmony_ci 0, 0, 14618c2ecf20Sopenharmony_ci DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, 14628c2ecf20Sopenharmony_ci 220000, 14638c2ecf20Sopenharmony_ci MGA_1164, 14648c2ecf20Sopenharmony_ci &vbMystique, 14658c2ecf20Sopenharmony_ci "Mystique 220 (PCI)"}, 14668c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS_AGP, 0x02, 14678c2ecf20Sopenharmony_ci 0, 0, 14688c2ecf20Sopenharmony_ci DEVF_VIDEO64BIT | DEVF_CROSS4MB, 14698c2ecf20Sopenharmony_ci 180000, 14708c2ecf20Sopenharmony_ci MGA_1064, 14718c2ecf20Sopenharmony_ci &vbMystique, 14728c2ecf20Sopenharmony_ci "Mystique (AGP)"}, 14738c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS_AGP, 0xFF, 14748c2ecf20Sopenharmony_ci 0, 0, 14758c2ecf20Sopenharmony_ci DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, 14768c2ecf20Sopenharmony_ci 220000, 14778c2ecf20Sopenharmony_ci MGA_1164, 14788c2ecf20Sopenharmony_ci &vbMystique, 14798c2ecf20Sopenharmony_ci "Mystique 220 (AGP)"}, 14808c2ecf20Sopenharmony_ci#endif 14818c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_G 14828c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, 14838c2ecf20Sopenharmony_ci 0, 0, 14848c2ecf20Sopenharmony_ci DEVF_G100, 14858c2ecf20Sopenharmony_ci 230000, 14868c2ecf20Sopenharmony_ci MGA_G100, 14878c2ecf20Sopenharmony_ci &vbG100, 14888c2ecf20Sopenharmony_ci "MGA-G100 (PCI)"}, 14898c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF, 14908c2ecf20Sopenharmony_ci 0, 0, 14918c2ecf20Sopenharmony_ci DEVF_G100, 14928c2ecf20Sopenharmony_ci 230000, 14938c2ecf20Sopenharmony_ci MGA_G100, 14948c2ecf20Sopenharmony_ci &vbG100, 14958c2ecf20Sopenharmony_ci "MGA-G100 (AGP)"}, 14968c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF, 14978c2ecf20Sopenharmony_ci 0, 0, 14988c2ecf20Sopenharmony_ci DEVF_G200, 14998c2ecf20Sopenharmony_ci 250000, 15008c2ecf20Sopenharmony_ci MGA_G200, 15018c2ecf20Sopenharmony_ci &vbG200, 15028c2ecf20Sopenharmony_ci "MGA-G200 (PCI)"}, 15038c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, 0x0532, 0xFF, 15048c2ecf20Sopenharmony_ci 0, 0, 15058c2ecf20Sopenharmony_ci DEVF_G200, 15068c2ecf20Sopenharmony_ci 250000, 15078c2ecf20Sopenharmony_ci MGA_G200, 15088c2ecf20Sopenharmony_ci &vbG200eW, 15098c2ecf20Sopenharmony_ci "MGA-G200eW (PCI)"}, 15108c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 15118c2ecf20Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC, 15128c2ecf20Sopenharmony_ci DEVF_G200, 15138c2ecf20Sopenharmony_ci 220000, 15148c2ecf20Sopenharmony_ci MGA_G200, 15158c2ecf20Sopenharmony_ci &vbG200, 15168c2ecf20Sopenharmony_ci "MGA-G200 (AGP)"}, 15178c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 15188c2ecf20Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP, 15198c2ecf20Sopenharmony_ci DEVF_G200, 15208c2ecf20Sopenharmony_ci 230000, 15218c2ecf20Sopenharmony_ci MGA_G200, 15228c2ecf20Sopenharmony_ci &vbG200, 15238c2ecf20Sopenharmony_ci "Mystique G200 (AGP)"}, 15248c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 15258c2ecf20Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP, 15268c2ecf20Sopenharmony_ci DEVF_G200, 15278c2ecf20Sopenharmony_ci 250000, 15288c2ecf20Sopenharmony_ci MGA_G200, 15298c2ecf20Sopenharmony_ci &vbG200, 15308c2ecf20Sopenharmony_ci "Millennium G200 (AGP)"}, 15318c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 15328c2ecf20Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP, 15338c2ecf20Sopenharmony_ci DEVF_G200, 15348c2ecf20Sopenharmony_ci 230000, 15358c2ecf20Sopenharmony_ci MGA_G200, 15368c2ecf20Sopenharmony_ci &vbG200, 15378c2ecf20Sopenharmony_ci "Marvel G200 (AGP)"}, 15388c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 15398c2ecf20Sopenharmony_ci PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP, 15408c2ecf20Sopenharmony_ci DEVF_G200, 15418c2ecf20Sopenharmony_ci 230000, 15428c2ecf20Sopenharmony_ci MGA_G200, 15438c2ecf20Sopenharmony_ci &vbG200, 15448c2ecf20Sopenharmony_ci "MGA-G200 (AGP)"}, 15458c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF, 15468c2ecf20Sopenharmony_ci 0, 0, 15478c2ecf20Sopenharmony_ci DEVF_G200, 15488c2ecf20Sopenharmony_ci 230000, 15498c2ecf20Sopenharmony_ci MGA_G200, 15508c2ecf20Sopenharmony_ci &vbG200, 15518c2ecf20Sopenharmony_ci "G200 (AGP)"}, 15528c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, 15538c2ecf20Sopenharmony_ci PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP, 15548c2ecf20Sopenharmony_ci DEVF_G400, 15558c2ecf20Sopenharmony_ci 360000, 15568c2ecf20Sopenharmony_ci MGA_G400, 15578c2ecf20Sopenharmony_ci &vbG400, 15588c2ecf20Sopenharmony_ci "Millennium G400 MAX (AGP)"}, 15598c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, 15608c2ecf20Sopenharmony_ci 0, 0, 15618c2ecf20Sopenharmony_ci DEVF_G400, 15628c2ecf20Sopenharmony_ci 300000, 15638c2ecf20Sopenharmony_ci MGA_G400, 15648c2ecf20Sopenharmony_ci &vbG400, 15658c2ecf20Sopenharmony_ci "G400 (AGP)"}, 15668c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0xFF, 15678c2ecf20Sopenharmony_ci 0, 0, 15688c2ecf20Sopenharmony_ci DEVF_G450, 15698c2ecf20Sopenharmony_ci 360000, 15708c2ecf20Sopenharmony_ci MGA_G450, 15718c2ecf20Sopenharmony_ci &vbG400, 15728c2ecf20Sopenharmony_ci "G450"}, 15738c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, 0xFF, 15748c2ecf20Sopenharmony_ci 0, 0, 15758c2ecf20Sopenharmony_ci DEVF_G550, 15768c2ecf20Sopenharmony_ci 360000, 15778c2ecf20Sopenharmony_ci MGA_G550, 15788c2ecf20Sopenharmony_ci &vbG400, 15798c2ecf20Sopenharmony_ci "G550"}, 15808c2ecf20Sopenharmony_ci#endif 15818c2ecf20Sopenharmony_ci {0, 0, 0xFF, 15828c2ecf20Sopenharmony_ci 0, 0, 15838c2ecf20Sopenharmony_ci 0, 15848c2ecf20Sopenharmony_ci 0, 15858c2ecf20Sopenharmony_ci 0, 15868c2ecf20Sopenharmony_ci NULL, 15878c2ecf20Sopenharmony_ci NULL}}; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci#ifndef MODULE 15908c2ecf20Sopenharmony_cistatic const struct fb_videomode defaultmode = { 15918c2ecf20Sopenharmony_ci /* 640x480 @ 60Hz, 31.5 kHz */ 15928c2ecf20Sopenharmony_ci NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, 15938c2ecf20Sopenharmony_ci 0, FB_VMODE_NONINTERLACED 15948c2ecf20Sopenharmony_ci}; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_cistatic int hotplug = 0; 15978c2ecf20Sopenharmony_ci#endif /* !MODULE */ 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_cistatic void setDefaultOutputs(struct matrox_fb_info *minfo) 16008c2ecf20Sopenharmony_ci{ 16018c2ecf20Sopenharmony_ci unsigned int i; 16028c2ecf20Sopenharmony_ci const char* ptr; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci minfo->outputs[0].default_src = MATROXFB_SRC_CRTC1; 16058c2ecf20Sopenharmony_ci if (minfo->devflags.g450dac) { 16068c2ecf20Sopenharmony_ci minfo->outputs[1].default_src = MATROXFB_SRC_CRTC1; 16078c2ecf20Sopenharmony_ci minfo->outputs[2].default_src = MATROXFB_SRC_CRTC1; 16088c2ecf20Sopenharmony_ci } else if (dfp) { 16098c2ecf20Sopenharmony_ci minfo->outputs[2].default_src = MATROXFB_SRC_CRTC1; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci ptr = outputs; 16128c2ecf20Sopenharmony_ci for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) { 16138c2ecf20Sopenharmony_ci char c = *ptr++; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (c == 0) { 16168c2ecf20Sopenharmony_ci break; 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci if (c == '0') { 16198c2ecf20Sopenharmony_ci minfo->outputs[i].default_src = MATROXFB_SRC_NONE; 16208c2ecf20Sopenharmony_ci } else if (c == '1') { 16218c2ecf20Sopenharmony_ci minfo->outputs[i].default_src = MATROXFB_SRC_CRTC1; 16228c2ecf20Sopenharmony_ci } else if (c == '2' && minfo->devflags.crtc2) { 16238c2ecf20Sopenharmony_ci minfo->outputs[i].default_src = MATROXFB_SRC_CRTC2; 16248c2ecf20Sopenharmony_ci } else { 16258c2ecf20Sopenharmony_ci printk(KERN_ERR "matroxfb: Unknown outputs setting\n"); 16268c2ecf20Sopenharmony_ci break; 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci /* Nullify this option for subsequent adapters */ 16308c2ecf20Sopenharmony_ci outputs[0] = 0; 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic int initMatrox2(struct matrox_fb_info *minfo, struct board *b) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci unsigned long ctrlptr_phys = 0; 16368c2ecf20Sopenharmony_ci unsigned long video_base_phys = 0; 16378c2ecf20Sopenharmony_ci unsigned int memsize; 16388c2ecf20Sopenharmony_ci int err; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci static const struct pci_device_id intel_82437[] = { 16418c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) }, 16428c2ecf20Sopenharmony_ci { }, 16438c2ecf20Sopenharmony_ci }; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci DBG(__func__) 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci /* set default values... */ 16488c2ecf20Sopenharmony_ci vesafb_defined.accel_flags = FB_ACCELF_TEXT; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci minfo->hw_switch = b->base->lowlevel; 16518c2ecf20Sopenharmony_ci minfo->devflags.accelerator = b->base->accelID; 16528c2ecf20Sopenharmony_ci minfo->max_pixel_clock = b->maxclk; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name); 16558c2ecf20Sopenharmony_ci minfo->capable.plnwt = 1; 16568c2ecf20Sopenharmony_ci minfo->chip = b->chip; 16578c2ecf20Sopenharmony_ci minfo->capable.srcorg = b->flags & DEVF_SRCORG; 16588c2ecf20Sopenharmony_ci minfo->devflags.video64bits = b->flags & DEVF_VIDEO64BIT; 16598c2ecf20Sopenharmony_ci if (b->flags & DEVF_TEXT4B) { 16608c2ecf20Sopenharmony_ci minfo->devflags.vgastep = 4; 16618c2ecf20Sopenharmony_ci minfo->devflags.textmode = 4; 16628c2ecf20Sopenharmony_ci minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP16; 16638c2ecf20Sopenharmony_ci } else if (b->flags & DEVF_TEXT16B) { 16648c2ecf20Sopenharmony_ci minfo->devflags.vgastep = 16; 16658c2ecf20Sopenharmony_ci minfo->devflags.textmode = 1; 16668c2ecf20Sopenharmony_ci minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP16; 16678c2ecf20Sopenharmony_ci } else { 16688c2ecf20Sopenharmony_ci minfo->devflags.vgastep = 8; 16698c2ecf20Sopenharmony_ci minfo->devflags.textmode = 1; 16708c2ecf20Sopenharmony_ci minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP8; 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci minfo->devflags.support32MB = (b->flags & DEVF_SUPPORT32MB) != 0; 16738c2ecf20Sopenharmony_ci minfo->devflags.precise_width = !(b->flags & DEVF_ANY_VXRES); 16748c2ecf20Sopenharmony_ci minfo->devflags.crtc2 = (b->flags & DEVF_CRTC2) != 0; 16758c2ecf20Sopenharmony_ci minfo->devflags.maven_capable = (b->flags & DEVF_MAVEN_CAPABLE) != 0; 16768c2ecf20Sopenharmony_ci minfo->devflags.dualhead = (b->flags & DEVF_DUALHEAD) != 0; 16778c2ecf20Sopenharmony_ci minfo->devflags.dfp_type = dfp_type; 16788c2ecf20Sopenharmony_ci minfo->devflags.g450dac = (b->flags & DEVF_G450DAC) != 0; 16798c2ecf20Sopenharmony_ci minfo->devflags.textstep = minfo->devflags.vgastep * minfo->devflags.textmode; 16808c2ecf20Sopenharmony_ci minfo->devflags.textvram = 65536 / minfo->devflags.textmode; 16818c2ecf20Sopenharmony_ci setDefaultOutputs(minfo); 16828c2ecf20Sopenharmony_ci if (b->flags & DEVF_PANELLINK_CAPABLE) { 16838c2ecf20Sopenharmony_ci minfo->outputs[2].data = minfo; 16848c2ecf20Sopenharmony_ci minfo->outputs[2].output = &panellink_output; 16858c2ecf20Sopenharmony_ci minfo->outputs[2].src = minfo->outputs[2].default_src; 16868c2ecf20Sopenharmony_ci minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR; 16878c2ecf20Sopenharmony_ci minfo->devflags.panellink = 1; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (minfo->capable.cross4MB < 0) 16918c2ecf20Sopenharmony_ci minfo->capable.cross4MB = b->flags & DEVF_CROSS4MB; 16928c2ecf20Sopenharmony_ci if (b->flags & DEVF_SWAPS) { 16938c2ecf20Sopenharmony_ci ctrlptr_phys = pci_resource_start(minfo->pcidev, 1); 16948c2ecf20Sopenharmony_ci video_base_phys = pci_resource_start(minfo->pcidev, 0); 16958c2ecf20Sopenharmony_ci minfo->devflags.fbResource = PCI_BASE_ADDRESS_0; 16968c2ecf20Sopenharmony_ci } else { 16978c2ecf20Sopenharmony_ci ctrlptr_phys = pci_resource_start(minfo->pcidev, 0); 16988c2ecf20Sopenharmony_ci video_base_phys = pci_resource_start(minfo->pcidev, 1); 16998c2ecf20Sopenharmony_ci minfo->devflags.fbResource = PCI_BASE_ADDRESS_1; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci err = -EINVAL; 17028c2ecf20Sopenharmony_ci if (!ctrlptr_phys) { 17038c2ecf20Sopenharmony_ci printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n"); 17048c2ecf20Sopenharmony_ci goto fail; 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci if (!video_base_phys) { 17078c2ecf20Sopenharmony_ci printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n"); 17088c2ecf20Sopenharmony_ci goto fail; 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci memsize = b->base->maxvram; 17118c2ecf20Sopenharmony_ci if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) { 17128c2ecf20Sopenharmony_ci goto fail; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) { 17158c2ecf20Sopenharmony_ci goto failCtrlMR; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci minfo->video.len_maximum = memsize; 17188c2ecf20Sopenharmony_ci /* convert mem (autodetect k, M) */ 17198c2ecf20Sopenharmony_ci if (mem < 1024) mem *= 1024; 17208c2ecf20Sopenharmony_ci if (mem < 0x00100000) mem *= 1024; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci if (mem && (mem < memsize)) 17238c2ecf20Sopenharmony_ci memsize = mem; 17248c2ecf20Sopenharmony_ci err = -ENOMEM; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci minfo->mmio.vbase.vaddr = ioremap(ctrlptr_phys, 16384); 17278c2ecf20Sopenharmony_ci if (!minfo->mmio.vbase.vaddr) { 17288c2ecf20Sopenharmony_ci printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys); 17298c2ecf20Sopenharmony_ci goto failVideoMR; 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci minfo->mmio.base = ctrlptr_phys; 17328c2ecf20Sopenharmony_ci minfo->mmio.len = 16384; 17338c2ecf20Sopenharmony_ci minfo->video.base = video_base_phys; 17348c2ecf20Sopenharmony_ci minfo->video.vbase.vaddr = ioremap_wc(video_base_phys, memsize); 17358c2ecf20Sopenharmony_ci if (!minfo->video.vbase.vaddr) { 17368c2ecf20Sopenharmony_ci printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n", 17378c2ecf20Sopenharmony_ci video_base_phys, memsize); 17388c2ecf20Sopenharmony_ci goto failCtrlIO; 17398c2ecf20Sopenharmony_ci } 17408c2ecf20Sopenharmony_ci { 17418c2ecf20Sopenharmony_ci u_int32_t cmd; 17428c2ecf20Sopenharmony_ci u_int32_t mga_option; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci pci_read_config_dword(minfo->pcidev, PCI_OPTION_REG, &mga_option); 17458c2ecf20Sopenharmony_ci pci_read_config_dword(minfo->pcidev, PCI_COMMAND, &cmd); 17468c2ecf20Sopenharmony_ci mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */ 17478c2ecf20Sopenharmony_ci mga_option |= MX_OPTION_BSWAP; 17488c2ecf20Sopenharmony_ci /* disable palette snooping */ 17498c2ecf20Sopenharmony_ci cmd &= ~PCI_COMMAND_VGA_PALETTE; 17508c2ecf20Sopenharmony_ci if (pci_dev_present(intel_82437)) { 17518c2ecf20Sopenharmony_ci if (!(mga_option & 0x20000000) && !minfo->devflags.nopciretry) { 17528c2ecf20Sopenharmony_ci printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n"); 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci mga_option |= 0x20000000; 17558c2ecf20Sopenharmony_ci minfo->devflags.nopciretry = 1; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci pci_write_config_dword(minfo->pcidev, PCI_COMMAND, cmd); 17588c2ecf20Sopenharmony_ci pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mga_option); 17598c2ecf20Sopenharmony_ci minfo->hw.MXoptionReg = mga_option; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */ 17628c2ecf20Sopenharmony_ci /* maybe preinit() candidate, but it is same... for all devices... at this time... */ 17638c2ecf20Sopenharmony_ci pci_write_config_dword(minfo->pcidev, PCI_MGA_INDEX, 0x00003C00); 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci err = -ENXIO; 17678c2ecf20Sopenharmony_ci matroxfb_read_pins(minfo); 17688c2ecf20Sopenharmony_ci if (minfo->hw_switch->preinit(minfo)) { 17698c2ecf20Sopenharmony_ci goto failVideoIO; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci err = -ENOMEM; 17738c2ecf20Sopenharmony_ci if (!matroxfb_getmemory(minfo, memsize, &minfo->video.len) || !minfo->video.len) { 17748c2ecf20Sopenharmony_ci printk(KERN_ERR "matroxfb: cannot determine memory size\n"); 17758c2ecf20Sopenharmony_ci goto failVideoIO; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci minfo->devflags.ydstorg = 0; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci minfo->video.base = video_base_phys; 17808c2ecf20Sopenharmony_ci minfo->video.len_usable = minfo->video.len; 17818c2ecf20Sopenharmony_ci if (minfo->video.len_usable > b->base->maxdisplayable) 17828c2ecf20Sopenharmony_ci minfo->video.len_usable = b->base->maxdisplayable; 17838c2ecf20Sopenharmony_ci if (mtrr) 17848c2ecf20Sopenharmony_ci minfo->wc_cookie = arch_phys_wc_add(video_base_phys, 17858c2ecf20Sopenharmony_ci minfo->video.len); 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci if (!minfo->devflags.novga) 17888c2ecf20Sopenharmony_ci request_region(0x3C0, 32, "matrox"); 17898c2ecf20Sopenharmony_ci matroxfb_g450_connect(minfo); 17908c2ecf20Sopenharmony_ci minfo->hw_switch->reset(minfo); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci minfo->fbcon.monspecs.hfmin = 0; 17938c2ecf20Sopenharmony_ci minfo->fbcon.monspecs.hfmax = fh; 17948c2ecf20Sopenharmony_ci minfo->fbcon.monspecs.vfmin = 0; 17958c2ecf20Sopenharmony_ci minfo->fbcon.monspecs.vfmax = fv; 17968c2ecf20Sopenharmony_ci minfo->fbcon.monspecs.dpms = 0; /* TBD */ 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci /* static settings */ 17998c2ecf20Sopenharmony_ci vesafb_defined.red = colors[depth-1].red; 18008c2ecf20Sopenharmony_ci vesafb_defined.green = colors[depth-1].green; 18018c2ecf20Sopenharmony_ci vesafb_defined.blue = colors[depth-1].blue; 18028c2ecf20Sopenharmony_ci vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel; 18038c2ecf20Sopenharmony_ci vesafb_defined.grayscale = grayscale; 18048c2ecf20Sopenharmony_ci vesafb_defined.vmode = 0; 18058c2ecf20Sopenharmony_ci if (noaccel) 18068c2ecf20Sopenharmony_ci vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci minfo->fbops = matroxfb_ops; 18098c2ecf20Sopenharmony_ci minfo->fbcon.fbops = &minfo->fbops; 18108c2ecf20Sopenharmony_ci minfo->fbcon.pseudo_palette = minfo->cmap; 18118c2ecf20Sopenharmony_ci minfo->fbcon.flags = FBINFO_PARTIAL_PAN_OK | /* Prefer panning for scroll under MC viewer/edit */ 18128c2ecf20Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | /* We have hw-assisted bmove */ 18138c2ecf20Sopenharmony_ci FBINFO_HWACCEL_FILLRECT | /* And fillrect */ 18148c2ecf20Sopenharmony_ci FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */ 18158c2ecf20Sopenharmony_ci FBINFO_HWACCEL_XPAN | /* And we support both horizontal */ 18168c2ecf20Sopenharmony_ci FBINFO_HWACCEL_YPAN | /* And vertical panning */ 18178c2ecf20Sopenharmony_ci FBINFO_READS_FAST; 18188c2ecf20Sopenharmony_ci minfo->video.len_usable &= PAGE_MASK; 18198c2ecf20Sopenharmony_ci fb_alloc_cmap(&minfo->fbcon.cmap, 256, 1); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci#ifndef MODULE 18228c2ecf20Sopenharmony_ci /* mode database is marked __init!!! */ 18238c2ecf20Sopenharmony_ci if (!hotplug) { 18248c2ecf20Sopenharmony_ci fb_find_mode(&vesafb_defined, &minfo->fbcon, videomode[0] ? videomode : NULL, 18258c2ecf20Sopenharmony_ci NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel); 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci#endif /* !MODULE */ 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci /* mode modifiers */ 18308c2ecf20Sopenharmony_ci if (hslen) 18318c2ecf20Sopenharmony_ci vesafb_defined.hsync_len = hslen; 18328c2ecf20Sopenharmony_ci if (vslen) 18338c2ecf20Sopenharmony_ci vesafb_defined.vsync_len = vslen; 18348c2ecf20Sopenharmony_ci if (left != ~0) 18358c2ecf20Sopenharmony_ci vesafb_defined.left_margin = left; 18368c2ecf20Sopenharmony_ci if (right != ~0) 18378c2ecf20Sopenharmony_ci vesafb_defined.right_margin = right; 18388c2ecf20Sopenharmony_ci if (upper != ~0) 18398c2ecf20Sopenharmony_ci vesafb_defined.upper_margin = upper; 18408c2ecf20Sopenharmony_ci if (lower != ~0) 18418c2ecf20Sopenharmony_ci vesafb_defined.lower_margin = lower; 18428c2ecf20Sopenharmony_ci if (xres) 18438c2ecf20Sopenharmony_ci vesafb_defined.xres = xres; 18448c2ecf20Sopenharmony_ci if (yres) 18458c2ecf20Sopenharmony_ci vesafb_defined.yres = yres; 18468c2ecf20Sopenharmony_ci if (sync != -1) 18478c2ecf20Sopenharmony_ci vesafb_defined.sync = sync; 18488c2ecf20Sopenharmony_ci else if (vesafb_defined.sync == ~0) { 18498c2ecf20Sopenharmony_ci vesafb_defined.sync = 0; 18508c2ecf20Sopenharmony_ci if (yres < 400) 18518c2ecf20Sopenharmony_ci vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT; 18528c2ecf20Sopenharmony_ci else if (yres < 480) 18538c2ecf20Sopenharmony_ci vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci /* fv, fh, maxclk limits was specified */ 18578c2ecf20Sopenharmony_ci { 18588c2ecf20Sopenharmony_ci unsigned int tmp; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if (fv) { 18618c2ecf20Sopenharmony_ci tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres 18628c2ecf20Sopenharmony_ci + vesafb_defined.lower_margin + vesafb_defined.vsync_len); 18638c2ecf20Sopenharmony_ci if ((tmp < fh) || (fh == 0)) fh = tmp; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci if (fh) { 18668c2ecf20Sopenharmony_ci tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres 18678c2ecf20Sopenharmony_ci + vesafb_defined.right_margin + vesafb_defined.hsync_len); 18688c2ecf20Sopenharmony_ci if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci tmp = (maxclk + 499) / 500; 18718c2ecf20Sopenharmony_ci if (tmp) { 18728c2ecf20Sopenharmony_ci tmp = (2000000000 + tmp) / tmp; 18738c2ecf20Sopenharmony_ci if (tmp > pixclock) pixclock = tmp; 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci if (pixclock) { 18778c2ecf20Sopenharmony_ci if (pixclock < 2000) /* > 500MHz */ 18788c2ecf20Sopenharmony_ci pixclock = 4000; /* 250MHz */ 18798c2ecf20Sopenharmony_ci if (pixclock > 1000000) 18808c2ecf20Sopenharmony_ci pixclock = 1000000; /* 1MHz */ 18818c2ecf20Sopenharmony_ci vesafb_defined.pixclock = pixclock; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci /* FIXME: Where to move this?! */ 18858c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC_PMAC) 18868c2ecf20Sopenharmony_ci#ifndef MODULE 18878c2ecf20Sopenharmony_ci if (machine_is(powermac)) { 18888c2ecf20Sopenharmony_ci struct fb_var_screeninfo var; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci if (default_vmode <= 0 || default_vmode > VMODE_MAX) 18918c2ecf20Sopenharmony_ci default_vmode = VMODE_640_480_60; 18928c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC32) 18938c2ecf20Sopenharmony_ci if (IS_REACHABLE(CONFIG_NVRAM) && default_cmode == CMODE_NVRAM) 18948c2ecf20Sopenharmony_ci default_cmode = nvram_read_byte(NV_CMODE); 18958c2ecf20Sopenharmony_ci#endif 18968c2ecf20Sopenharmony_ci if (default_cmode < CMODE_8 || default_cmode > CMODE_32) 18978c2ecf20Sopenharmony_ci default_cmode = CMODE_8; 18988c2ecf20Sopenharmony_ci if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) { 18998c2ecf20Sopenharmony_ci var.accel_flags = vesafb_defined.accel_flags; 19008c2ecf20Sopenharmony_ci var.xoffset = var.yoffset = 0; 19018c2ecf20Sopenharmony_ci /* Note: mac_vmode_to_var() does not set all parameters */ 19028c2ecf20Sopenharmony_ci vesafb_defined = var; 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci#endif /* !MODULE */ 19068c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_PMAC */ 19078c2ecf20Sopenharmony_ci vesafb_defined.xres_virtual = vesafb_defined.xres; 19088c2ecf20Sopenharmony_ci if (nopan) { 19098c2ecf20Sopenharmony_ci vesafb_defined.yres_virtual = vesafb_defined.yres; 19108c2ecf20Sopenharmony_ci } else { 19118c2ecf20Sopenharmony_ci vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough 19128c2ecf20Sopenharmony_ci to yres_virtual * xres_virtual < 2^32 */ 19138c2ecf20Sopenharmony_ci } 19148c2ecf20Sopenharmony_ci matroxfb_init_fix(minfo); 19158c2ecf20Sopenharmony_ci minfo->fbcon.screen_base = vaddr_va(minfo->video.vbase); 19168c2ecf20Sopenharmony_ci /* Normalize values (namely yres_virtual) */ 19178c2ecf20Sopenharmony_ci matroxfb_check_var(&vesafb_defined, &minfo->fbcon); 19188c2ecf20Sopenharmony_ci /* And put it into "current" var. Do NOT program hardware yet, or we'll not take over 19198c2ecf20Sopenharmony_ci * vgacon correctly. fbcon_startup will call fb_set_par for us, WITHOUT check_var, 19208c2ecf20Sopenharmony_ci * and unfortunately it will do it BEFORE vgacon contents is saved, so it won't work 19218c2ecf20Sopenharmony_ci * anyway. But we at least tried... */ 19228c2ecf20Sopenharmony_ci minfo->fbcon.var = vesafb_defined; 19238c2ecf20Sopenharmony_ci err = -EINVAL; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n", 19268c2ecf20Sopenharmony_ci vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, 19278c2ecf20Sopenharmony_ci vesafb_defined.xres_virtual, vesafb_defined.yres_virtual); 19288c2ecf20Sopenharmony_ci printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n", 19298c2ecf20Sopenharmony_ci minfo->video.base, vaddr_va(minfo->video.vbase), minfo->video.len); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci/* We do not have to set currcon to 0... register_framebuffer do it for us on first console 19328c2ecf20Sopenharmony_ci * and we do not want currcon == 0 for subsequent framebuffers */ 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci minfo->fbcon.device = &minfo->pcidev->dev; 19358c2ecf20Sopenharmony_ci if (register_framebuffer(&minfo->fbcon) < 0) { 19368c2ecf20Sopenharmony_ci goto failVideoIO; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci fb_info(&minfo->fbcon, "%s frame buffer device\n", minfo->fbcon.fix.id); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci /* there is no console on this fb... but we have to initialize hardware 19418c2ecf20Sopenharmony_ci * until someone tells me what is proper thing to do */ 19428c2ecf20Sopenharmony_ci if (!minfo->initialized) { 19438c2ecf20Sopenharmony_ci fb_info(&minfo->fbcon, "initializing hardware\n"); 19448c2ecf20Sopenharmony_ci /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var 19458c2ecf20Sopenharmony_ci * already before, so register_framebuffer works correctly. */ 19468c2ecf20Sopenharmony_ci vesafb_defined.activate |= FB_ACTIVATE_FORCE; 19478c2ecf20Sopenharmony_ci fb_set_var(&minfo->fbcon, &vesafb_defined); 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci return 0; 19518c2ecf20Sopenharmony_cifailVideoIO:; 19528c2ecf20Sopenharmony_ci matroxfb_g450_shutdown(minfo); 19538c2ecf20Sopenharmony_ci iounmap(minfo->video.vbase.vaddr); 19548c2ecf20Sopenharmony_cifailCtrlIO:; 19558c2ecf20Sopenharmony_ci iounmap(minfo->mmio.vbase.vaddr); 19568c2ecf20Sopenharmony_cifailVideoMR:; 19578c2ecf20Sopenharmony_ci release_mem_region(video_base_phys, minfo->video.len_maximum); 19588c2ecf20Sopenharmony_cifailCtrlMR:; 19598c2ecf20Sopenharmony_ci release_mem_region(ctrlptr_phys, 16384); 19608c2ecf20Sopenharmony_cifail:; 19618c2ecf20Sopenharmony_ci return err; 19628c2ecf20Sopenharmony_ci} 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_cistatic LIST_HEAD(matroxfb_list); 19658c2ecf20Sopenharmony_cistatic LIST_HEAD(matroxfb_driver_list); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci#define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb) 19688c2ecf20Sopenharmony_ci#define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node) 19698c2ecf20Sopenharmony_ciint matroxfb_register_driver(struct matroxfb_driver* drv) { 19708c2ecf20Sopenharmony_ci struct matrox_fb_info* minfo; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci list_add(&drv->node, &matroxfb_driver_list); 19738c2ecf20Sopenharmony_ci for (minfo = matroxfb_l(matroxfb_list.next); 19748c2ecf20Sopenharmony_ci minfo != matroxfb_l(&matroxfb_list); 19758c2ecf20Sopenharmony_ci minfo = matroxfb_l(minfo->next_fb.next)) { 19768c2ecf20Sopenharmony_ci void* p; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (minfo->drivers_count == MATROXFB_MAX_FB_DRIVERS) 19798c2ecf20Sopenharmony_ci continue; 19808c2ecf20Sopenharmony_ci p = drv->probe(minfo); 19818c2ecf20Sopenharmony_ci if (p) { 19828c2ecf20Sopenharmony_ci minfo->drivers_data[minfo->drivers_count] = p; 19838c2ecf20Sopenharmony_ci minfo->drivers[minfo->drivers_count++] = drv; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci return 0; 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_civoid matroxfb_unregister_driver(struct matroxfb_driver* drv) { 19908c2ecf20Sopenharmony_ci struct matrox_fb_info* minfo; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci list_del(&drv->node); 19938c2ecf20Sopenharmony_ci for (minfo = matroxfb_l(matroxfb_list.next); 19948c2ecf20Sopenharmony_ci minfo != matroxfb_l(&matroxfb_list); 19958c2ecf20Sopenharmony_ci minfo = matroxfb_l(minfo->next_fb.next)) { 19968c2ecf20Sopenharmony_ci int i; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci for (i = 0; i < minfo->drivers_count; ) { 19998c2ecf20Sopenharmony_ci if (minfo->drivers[i] == drv) { 20008c2ecf20Sopenharmony_ci if (drv && drv->remove) 20018c2ecf20Sopenharmony_ci drv->remove(minfo, minfo->drivers_data[i]); 20028c2ecf20Sopenharmony_ci minfo->drivers[i] = minfo->drivers[--minfo->drivers_count]; 20038c2ecf20Sopenharmony_ci minfo->drivers_data[i] = minfo->drivers_data[minfo->drivers_count]; 20048c2ecf20Sopenharmony_ci } else 20058c2ecf20Sopenharmony_ci i++; 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci } 20088c2ecf20Sopenharmony_ci} 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_cistatic void matroxfb_register_device(struct matrox_fb_info* minfo) { 20118c2ecf20Sopenharmony_ci struct matroxfb_driver* drv; 20128c2ecf20Sopenharmony_ci int i = 0; 20138c2ecf20Sopenharmony_ci list_add(&minfo->next_fb, &matroxfb_list); 20148c2ecf20Sopenharmony_ci for (drv = matroxfb_driver_l(matroxfb_driver_list.next); 20158c2ecf20Sopenharmony_ci drv != matroxfb_driver_l(&matroxfb_driver_list); 20168c2ecf20Sopenharmony_ci drv = matroxfb_driver_l(drv->node.next)) { 20178c2ecf20Sopenharmony_ci if (drv->probe) { 20188c2ecf20Sopenharmony_ci void *p = drv->probe(minfo); 20198c2ecf20Sopenharmony_ci if (p) { 20208c2ecf20Sopenharmony_ci minfo->drivers_data[i] = p; 20218c2ecf20Sopenharmony_ci minfo->drivers[i++] = drv; 20228c2ecf20Sopenharmony_ci if (i == MATROXFB_MAX_FB_DRIVERS) 20238c2ecf20Sopenharmony_ci break; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci minfo->drivers_count = i; 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_cistatic void matroxfb_unregister_device(struct matrox_fb_info* minfo) { 20318c2ecf20Sopenharmony_ci int i; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci list_del(&minfo->next_fb); 20348c2ecf20Sopenharmony_ci for (i = 0; i < minfo->drivers_count; i++) { 20358c2ecf20Sopenharmony_ci struct matroxfb_driver* drv = minfo->drivers[i]; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci if (drv && drv->remove) 20388c2ecf20Sopenharmony_ci drv->remove(minfo, minfo->drivers_data[i]); 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) { 20438c2ecf20Sopenharmony_ci struct board* b; 20448c2ecf20Sopenharmony_ci u_int16_t svid; 20458c2ecf20Sopenharmony_ci u_int16_t sid; 20468c2ecf20Sopenharmony_ci struct matrox_fb_info* minfo; 20478c2ecf20Sopenharmony_ci int err; 20488c2ecf20Sopenharmony_ci u_int32_t cmd; 20498c2ecf20Sopenharmony_ci DBG(__func__) 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci svid = pdev->subsystem_vendor; 20528c2ecf20Sopenharmony_ci sid = pdev->subsystem_device; 20538c2ecf20Sopenharmony_ci for (b = dev_list; b->vendor; b++) { 20548c2ecf20Sopenharmony_ci if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < pdev->revision)) continue; 20558c2ecf20Sopenharmony_ci if (b->svid) 20568c2ecf20Sopenharmony_ci if ((b->svid != svid) || (b->sid != sid)) continue; 20578c2ecf20Sopenharmony_ci break; 20588c2ecf20Sopenharmony_ci } 20598c2ecf20Sopenharmony_ci /* not match... */ 20608c2ecf20Sopenharmony_ci if (!b->vendor) 20618c2ecf20Sopenharmony_ci return -ENODEV; 20628c2ecf20Sopenharmony_ci if (dev > 0) { 20638c2ecf20Sopenharmony_ci /* not requested one... */ 20648c2ecf20Sopenharmony_ci dev--; 20658c2ecf20Sopenharmony_ci return -ENODEV; 20668c2ecf20Sopenharmony_ci } 20678c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, PCI_COMMAND, &cmd); 20688c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 20698c2ecf20Sopenharmony_ci return -1; 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci minfo = kzalloc(sizeof(*minfo), GFP_KERNEL); 20738c2ecf20Sopenharmony_ci if (!minfo) 20748c2ecf20Sopenharmony_ci return -ENOMEM; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci minfo->pcidev = pdev; 20778c2ecf20Sopenharmony_ci minfo->dead = 0; 20788c2ecf20Sopenharmony_ci minfo->usecount = 0; 20798c2ecf20Sopenharmony_ci minfo->userusecount = 0; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, minfo); 20828c2ecf20Sopenharmony_ci /* DEVFLAGS */ 20838c2ecf20Sopenharmony_ci minfo->devflags.memtype = memtype; 20848c2ecf20Sopenharmony_ci if (memtype != -1) 20858c2ecf20Sopenharmony_ci noinit = 0; 20868c2ecf20Sopenharmony_ci if (cmd & PCI_COMMAND_MEMORY) { 20878c2ecf20Sopenharmony_ci minfo->devflags.novga = novga; 20888c2ecf20Sopenharmony_ci minfo->devflags.nobios = nobios; 20898c2ecf20Sopenharmony_ci minfo->devflags.noinit = noinit; 20908c2ecf20Sopenharmony_ci /* subsequent heads always needs initialization and must not enable BIOS */ 20918c2ecf20Sopenharmony_ci novga = 1; 20928c2ecf20Sopenharmony_ci nobios = 1; 20938c2ecf20Sopenharmony_ci noinit = 0; 20948c2ecf20Sopenharmony_ci } else { 20958c2ecf20Sopenharmony_ci minfo->devflags.novga = 1; 20968c2ecf20Sopenharmony_ci minfo->devflags.nobios = 1; 20978c2ecf20Sopenharmony_ci minfo->devflags.noinit = 0; 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci minfo->devflags.nopciretry = no_pci_retry; 21018c2ecf20Sopenharmony_ci minfo->devflags.mga_24bpp_fix = inv24; 21028c2ecf20Sopenharmony_ci minfo->devflags.precise_width = option_precise_width; 21038c2ecf20Sopenharmony_ci minfo->devflags.sgram = sgram; 21048c2ecf20Sopenharmony_ci minfo->capable.cross4MB = cross4MB; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci spin_lock_init(&minfo->lock.DAC); 21078c2ecf20Sopenharmony_ci spin_lock_init(&minfo->lock.accel); 21088c2ecf20Sopenharmony_ci init_rwsem(&minfo->crtc2.lock); 21098c2ecf20Sopenharmony_ci init_rwsem(&minfo->altout.lock); 21108c2ecf20Sopenharmony_ci mutex_init(&minfo->fbcon.mm_lock); 21118c2ecf20Sopenharmony_ci minfo->irq_flags = 0; 21128c2ecf20Sopenharmony_ci init_waitqueue_head(&minfo->crtc1.vsync.wait); 21138c2ecf20Sopenharmony_ci init_waitqueue_head(&minfo->crtc2.vsync.wait); 21148c2ecf20Sopenharmony_ci minfo->crtc1.panpos = -1; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci err = initMatrox2(minfo, b); 21178c2ecf20Sopenharmony_ci if (!err) { 21188c2ecf20Sopenharmony_ci matroxfb_register_device(minfo); 21198c2ecf20Sopenharmony_ci return 0; 21208c2ecf20Sopenharmony_ci } 21218c2ecf20Sopenharmony_ci kfree(minfo); 21228c2ecf20Sopenharmony_ci return -1; 21238c2ecf20Sopenharmony_ci} 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_cistatic void pci_remove_matrox(struct pci_dev* pdev) { 21268c2ecf20Sopenharmony_ci struct matrox_fb_info* minfo; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci minfo = pci_get_drvdata(pdev); 21298c2ecf20Sopenharmony_ci matroxfb_remove(minfo, 1); 21308c2ecf20Sopenharmony_ci} 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_cistatic const struct pci_device_id matroxfb_devices[] = { 21338c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MILLENIUM 21348c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 21358c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21368c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 21378c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21388c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 21398c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21408c2ecf20Sopenharmony_ci#endif 21418c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_MYSTIQUE 21428c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 21438c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21448c2ecf20Sopenharmony_ci#endif 21458c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_MATROX_G 21468c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 21478c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21488c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 21498c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21508c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 21518c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21528c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, 0x0532, 21538c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21548c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 21558c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21568c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 21578c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21588c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, 21598c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 21608c2ecf20Sopenharmony_ci#endif 21618c2ecf20Sopenharmony_ci {0, 0, 21628c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0} 21638c2ecf20Sopenharmony_ci}; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, matroxfb_devices); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_cistatic struct pci_driver matroxfb_driver = { 21698c2ecf20Sopenharmony_ci .name = "matroxfb", 21708c2ecf20Sopenharmony_ci .id_table = matroxfb_devices, 21718c2ecf20Sopenharmony_ci .probe = matroxfb_probe, 21728c2ecf20Sopenharmony_ci .remove = pci_remove_matrox, 21738c2ecf20Sopenharmony_ci}; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci/* **************************** init-time only **************************** */ 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci#define RSResolution(X) ((X) & 0x0F) 21788c2ecf20Sopenharmony_ci#define RS640x400 1 21798c2ecf20Sopenharmony_ci#define RS640x480 2 21808c2ecf20Sopenharmony_ci#define RS800x600 3 21818c2ecf20Sopenharmony_ci#define RS1024x768 4 21828c2ecf20Sopenharmony_ci#define RS1280x1024 5 21838c2ecf20Sopenharmony_ci#define RS1600x1200 6 21848c2ecf20Sopenharmony_ci#define RS768x576 7 21858c2ecf20Sopenharmony_ci#define RS960x720 8 21868c2ecf20Sopenharmony_ci#define RS1152x864 9 21878c2ecf20Sopenharmony_ci#define RS1408x1056 10 21888c2ecf20Sopenharmony_ci#define RS640x350 11 21898c2ecf20Sopenharmony_ci#define RS1056x344 12 /* 132 x 43 text */ 21908c2ecf20Sopenharmony_ci#define RS1056x400 13 /* 132 x 50 text */ 21918c2ecf20Sopenharmony_ci#define RS1056x480 14 /* 132 x 60 text */ 21928c2ecf20Sopenharmony_ci#define RSNoxNo 15 21938c2ecf20Sopenharmony_ci/* 10-FF */ 21948c2ecf20Sopenharmony_cistatic struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = { 21958c2ecf20Sopenharmony_ci { 640, 400, 48, 16, 39, 8, 96, 2, 70 }, 21968c2ecf20Sopenharmony_ci { 640, 480, 48, 16, 33, 10, 96, 2, 60 }, 21978c2ecf20Sopenharmony_ci { 800, 600, 144, 24, 28, 8, 112, 6, 60 }, 21988c2ecf20Sopenharmony_ci { 1024, 768, 160, 32, 30, 4, 128, 4, 60 }, 21998c2ecf20Sopenharmony_ci { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 }, 22008c2ecf20Sopenharmony_ci { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 }, 22018c2ecf20Sopenharmony_ci { 768, 576, 144, 16, 28, 6, 112, 4, 60 }, 22028c2ecf20Sopenharmony_ci { 960, 720, 144, 24, 28, 8, 112, 4, 60 }, 22038c2ecf20Sopenharmony_ci { 1152, 864, 192, 32, 30, 4, 128, 4, 60 }, 22048c2ecf20Sopenharmony_ci { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 }, 22058c2ecf20Sopenharmony_ci { 640, 350, 48, 16, 39, 8, 96, 2, 70 }, 22068c2ecf20Sopenharmony_ci { 1056, 344, 96, 24, 59, 44, 160, 2, 70 }, 22078c2ecf20Sopenharmony_ci { 1056, 400, 96, 24, 39, 8, 160, 2, 70 }, 22088c2ecf20Sopenharmony_ci { 1056, 480, 96, 24, 36, 12, 160, 3, 60 }, 22098c2ecf20Sopenharmony_ci { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 } 22108c2ecf20Sopenharmony_ci}; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci#define RSCreate(X,Y) ((X) | ((Y) << 8)) 22138c2ecf20Sopenharmony_cistatic struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = { 22148c2ecf20Sopenharmony_ci/* default must be first */ 22158c2ecf20Sopenharmony_ci { ~0, RSCreate(RSNoxNo, RS8bpp ) }, 22168c2ecf20Sopenharmony_ci { 0x101, RSCreate(RS640x480, RS8bpp ) }, 22178c2ecf20Sopenharmony_ci { 0x100, RSCreate(RS640x400, RS8bpp ) }, 22188c2ecf20Sopenharmony_ci { 0x180, RSCreate(RS768x576, RS8bpp ) }, 22198c2ecf20Sopenharmony_ci { 0x103, RSCreate(RS800x600, RS8bpp ) }, 22208c2ecf20Sopenharmony_ci { 0x188, RSCreate(RS960x720, RS8bpp ) }, 22218c2ecf20Sopenharmony_ci { 0x105, RSCreate(RS1024x768, RS8bpp ) }, 22228c2ecf20Sopenharmony_ci { 0x190, RSCreate(RS1152x864, RS8bpp ) }, 22238c2ecf20Sopenharmony_ci { 0x107, RSCreate(RS1280x1024, RS8bpp ) }, 22248c2ecf20Sopenharmony_ci { 0x198, RSCreate(RS1408x1056, RS8bpp ) }, 22258c2ecf20Sopenharmony_ci { 0x11C, RSCreate(RS1600x1200, RS8bpp ) }, 22268c2ecf20Sopenharmony_ci { 0x110, RSCreate(RS640x480, RS15bpp) }, 22278c2ecf20Sopenharmony_ci { 0x181, RSCreate(RS768x576, RS15bpp) }, 22288c2ecf20Sopenharmony_ci { 0x113, RSCreate(RS800x600, RS15bpp) }, 22298c2ecf20Sopenharmony_ci { 0x189, RSCreate(RS960x720, RS15bpp) }, 22308c2ecf20Sopenharmony_ci { 0x116, RSCreate(RS1024x768, RS15bpp) }, 22318c2ecf20Sopenharmony_ci { 0x191, RSCreate(RS1152x864, RS15bpp) }, 22328c2ecf20Sopenharmony_ci { 0x119, RSCreate(RS1280x1024, RS15bpp) }, 22338c2ecf20Sopenharmony_ci { 0x199, RSCreate(RS1408x1056, RS15bpp) }, 22348c2ecf20Sopenharmony_ci { 0x11D, RSCreate(RS1600x1200, RS15bpp) }, 22358c2ecf20Sopenharmony_ci { 0x111, RSCreate(RS640x480, RS16bpp) }, 22368c2ecf20Sopenharmony_ci { 0x182, RSCreate(RS768x576, RS16bpp) }, 22378c2ecf20Sopenharmony_ci { 0x114, RSCreate(RS800x600, RS16bpp) }, 22388c2ecf20Sopenharmony_ci { 0x18A, RSCreate(RS960x720, RS16bpp) }, 22398c2ecf20Sopenharmony_ci { 0x117, RSCreate(RS1024x768, RS16bpp) }, 22408c2ecf20Sopenharmony_ci { 0x192, RSCreate(RS1152x864, RS16bpp) }, 22418c2ecf20Sopenharmony_ci { 0x11A, RSCreate(RS1280x1024, RS16bpp) }, 22428c2ecf20Sopenharmony_ci { 0x19A, RSCreate(RS1408x1056, RS16bpp) }, 22438c2ecf20Sopenharmony_ci { 0x11E, RSCreate(RS1600x1200, RS16bpp) }, 22448c2ecf20Sopenharmony_ci { 0x1B2, RSCreate(RS640x480, RS24bpp) }, 22458c2ecf20Sopenharmony_ci { 0x184, RSCreate(RS768x576, RS24bpp) }, 22468c2ecf20Sopenharmony_ci { 0x1B5, RSCreate(RS800x600, RS24bpp) }, 22478c2ecf20Sopenharmony_ci { 0x18C, RSCreate(RS960x720, RS24bpp) }, 22488c2ecf20Sopenharmony_ci { 0x1B8, RSCreate(RS1024x768, RS24bpp) }, 22498c2ecf20Sopenharmony_ci { 0x194, RSCreate(RS1152x864, RS24bpp) }, 22508c2ecf20Sopenharmony_ci { 0x1BB, RSCreate(RS1280x1024, RS24bpp) }, 22518c2ecf20Sopenharmony_ci { 0x19C, RSCreate(RS1408x1056, RS24bpp) }, 22528c2ecf20Sopenharmony_ci { 0x1BF, RSCreate(RS1600x1200, RS24bpp) }, 22538c2ecf20Sopenharmony_ci { 0x112, RSCreate(RS640x480, RS32bpp) }, 22548c2ecf20Sopenharmony_ci { 0x183, RSCreate(RS768x576, RS32bpp) }, 22558c2ecf20Sopenharmony_ci { 0x115, RSCreate(RS800x600, RS32bpp) }, 22568c2ecf20Sopenharmony_ci { 0x18B, RSCreate(RS960x720, RS32bpp) }, 22578c2ecf20Sopenharmony_ci { 0x118, RSCreate(RS1024x768, RS32bpp) }, 22588c2ecf20Sopenharmony_ci { 0x193, RSCreate(RS1152x864, RS32bpp) }, 22598c2ecf20Sopenharmony_ci { 0x11B, RSCreate(RS1280x1024, RS32bpp) }, 22608c2ecf20Sopenharmony_ci { 0x19B, RSCreate(RS1408x1056, RS32bpp) }, 22618c2ecf20Sopenharmony_ci { 0x11F, RSCreate(RS1600x1200, RS32bpp) }, 22628c2ecf20Sopenharmony_ci { 0x010, RSCreate(RS640x350, RS4bpp ) }, 22638c2ecf20Sopenharmony_ci { 0x012, RSCreate(RS640x480, RS4bpp ) }, 22648c2ecf20Sopenharmony_ci { 0x102, RSCreate(RS800x600, RS4bpp ) }, 22658c2ecf20Sopenharmony_ci { 0x104, RSCreate(RS1024x768, RS4bpp ) }, 22668c2ecf20Sopenharmony_ci { 0x106, RSCreate(RS1280x1024, RS4bpp ) }, 22678c2ecf20Sopenharmony_ci { 0, 0 }}; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_cistatic void __init matroxfb_init_params(void) { 22708c2ecf20Sopenharmony_ci /* fh from kHz to Hz */ 22718c2ecf20Sopenharmony_ci if (fh < 1000) 22728c2ecf20Sopenharmony_ci fh *= 1000; /* 1kHz minimum */ 22738c2ecf20Sopenharmony_ci /* maxclk */ 22748c2ecf20Sopenharmony_ci if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */ 22758c2ecf20Sopenharmony_ci if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */ 22768c2ecf20Sopenharmony_ci /* fix VESA number */ 22778c2ecf20Sopenharmony_ci if (vesa != ~0) 22788c2ecf20Sopenharmony_ci vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */ 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci /* static settings */ 22818c2ecf20Sopenharmony_ci for (RSptr = vesamap; RSptr->vesa; RSptr++) { 22828c2ecf20Sopenharmony_ci if (RSptr->vesa == vesa) break; 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci if (!RSptr->vesa) { 22858c2ecf20Sopenharmony_ci printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa); 22868c2ecf20Sopenharmony_ci RSptr = vesamap; 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci { 22898c2ecf20Sopenharmony_ci int res = RSResolution(RSptr->info)-1; 22908c2ecf20Sopenharmony_ci if (left == ~0) 22918c2ecf20Sopenharmony_ci left = timmings[res].left; 22928c2ecf20Sopenharmony_ci if (!xres) 22938c2ecf20Sopenharmony_ci xres = timmings[res].xres; 22948c2ecf20Sopenharmony_ci if (right == ~0) 22958c2ecf20Sopenharmony_ci right = timmings[res].right; 22968c2ecf20Sopenharmony_ci if (!hslen) 22978c2ecf20Sopenharmony_ci hslen = timmings[res].hslen; 22988c2ecf20Sopenharmony_ci if (upper == ~0) 22998c2ecf20Sopenharmony_ci upper = timmings[res].upper; 23008c2ecf20Sopenharmony_ci if (!yres) 23018c2ecf20Sopenharmony_ci yres = timmings[res].yres; 23028c2ecf20Sopenharmony_ci if (lower == ~0) 23038c2ecf20Sopenharmony_ci lower = timmings[res].lower; 23048c2ecf20Sopenharmony_ci if (!vslen) 23058c2ecf20Sopenharmony_ci vslen = timmings[res].vslen; 23068c2ecf20Sopenharmony_ci if (!(fv||fh||maxclk||pixclock)) 23078c2ecf20Sopenharmony_ci fv = timmings[res].vfreq; 23088c2ecf20Sopenharmony_ci if (depth == -1) 23098c2ecf20Sopenharmony_ci depth = RSDepth(RSptr->info); 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci} 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_cistatic int __init matrox_init(void) { 23148c2ecf20Sopenharmony_ci int err; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci matroxfb_init_params(); 23178c2ecf20Sopenharmony_ci err = pci_register_driver(&matroxfb_driver); 23188c2ecf20Sopenharmony_ci dev = -1; /* accept all new devices... */ 23198c2ecf20Sopenharmony_ci return err; 23208c2ecf20Sopenharmony_ci} 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci/* **************************** exit-time only **************************** */ 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_cistatic void __exit matrox_done(void) { 23258c2ecf20Sopenharmony_ci pci_unregister_driver(&matroxfb_driver); 23268c2ecf20Sopenharmony_ci} 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci#ifndef MODULE 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci/* ************************* init in-kernel code ************************** */ 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_cistatic int __init matroxfb_setup(char *options) { 23338c2ecf20Sopenharmony_ci char *this_opt; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci DBG(__func__) 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci if (!options || !*options) 23388c2ecf20Sopenharmony_ci return 0; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 23418c2ecf20Sopenharmony_ci if (!*this_opt) continue; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci dprintk("matroxfb_setup: option %s\n", this_opt); 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci if (!strncmp(this_opt, "dev:", 4)) 23468c2ecf20Sopenharmony_ci dev = simple_strtoul(this_opt+4, NULL, 0); 23478c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "depth:", 6)) { 23488c2ecf20Sopenharmony_ci switch (simple_strtoul(this_opt+6, NULL, 0)) { 23498c2ecf20Sopenharmony_ci case 0: depth = RSText; break; 23508c2ecf20Sopenharmony_ci case 4: depth = RS4bpp; break; 23518c2ecf20Sopenharmony_ci case 8: depth = RS8bpp; break; 23528c2ecf20Sopenharmony_ci case 15:depth = RS15bpp; break; 23538c2ecf20Sopenharmony_ci case 16:depth = RS16bpp; break; 23548c2ecf20Sopenharmony_ci case 24:depth = RS24bpp; break; 23558c2ecf20Sopenharmony_ci case 32:depth = RS32bpp; break; 23568c2ecf20Sopenharmony_ci default: 23578c2ecf20Sopenharmony_ci printk(KERN_ERR "matroxfb: unsupported color depth\n"); 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci } else if (!strncmp(this_opt, "xres:", 5)) 23608c2ecf20Sopenharmony_ci xres = simple_strtoul(this_opt+5, NULL, 0); 23618c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "yres:", 5)) 23628c2ecf20Sopenharmony_ci yres = simple_strtoul(this_opt+5, NULL, 0); 23638c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "vslen:", 6)) 23648c2ecf20Sopenharmony_ci vslen = simple_strtoul(this_opt+6, NULL, 0); 23658c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "hslen:", 6)) 23668c2ecf20Sopenharmony_ci hslen = simple_strtoul(this_opt+6, NULL, 0); 23678c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "left:", 5)) 23688c2ecf20Sopenharmony_ci left = simple_strtoul(this_opt+5, NULL, 0); 23698c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "right:", 6)) 23708c2ecf20Sopenharmony_ci right = simple_strtoul(this_opt+6, NULL, 0); 23718c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "upper:", 6)) 23728c2ecf20Sopenharmony_ci upper = simple_strtoul(this_opt+6, NULL, 0); 23738c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "lower:", 6)) 23748c2ecf20Sopenharmony_ci lower = simple_strtoul(this_opt+6, NULL, 0); 23758c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "pixclock:", 9)) 23768c2ecf20Sopenharmony_ci pixclock = simple_strtoul(this_opt+9, NULL, 0); 23778c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "sync:", 5)) 23788c2ecf20Sopenharmony_ci sync = simple_strtoul(this_opt+5, NULL, 0); 23798c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "vesa:", 5)) 23808c2ecf20Sopenharmony_ci vesa = simple_strtoul(this_opt+5, NULL, 0); 23818c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "maxclk:", 7)) 23828c2ecf20Sopenharmony_ci maxclk = simple_strtoul(this_opt+7, NULL, 0); 23838c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "fh:", 3)) 23848c2ecf20Sopenharmony_ci fh = simple_strtoul(this_opt+3, NULL, 0); 23858c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "fv:", 3)) 23868c2ecf20Sopenharmony_ci fv = simple_strtoul(this_opt+3, NULL, 0); 23878c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "mem:", 4)) 23888c2ecf20Sopenharmony_ci mem = simple_strtoul(this_opt+4, NULL, 0); 23898c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "mode:", 5)) 23908c2ecf20Sopenharmony_ci strlcpy(videomode, this_opt+5, sizeof(videomode)); 23918c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "outputs:", 8)) 23928c2ecf20Sopenharmony_ci strlcpy(outputs, this_opt+8, sizeof(outputs)); 23938c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "dfp:", 4)) { 23948c2ecf20Sopenharmony_ci dfp_type = simple_strtoul(this_opt+4, NULL, 0); 23958c2ecf20Sopenharmony_ci dfp = 1; 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 23988c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "vmode:", 6)) { 23998c2ecf20Sopenharmony_ci unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); 24008c2ecf20Sopenharmony_ci if (vmode > 0 && vmode <= VMODE_MAX) 24018c2ecf20Sopenharmony_ci default_vmode = vmode; 24028c2ecf20Sopenharmony_ci } else if (!strncmp(this_opt, "cmode:", 6)) { 24038c2ecf20Sopenharmony_ci unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); 24048c2ecf20Sopenharmony_ci switch (cmode) { 24058c2ecf20Sopenharmony_ci case 0: 24068c2ecf20Sopenharmony_ci case 8: 24078c2ecf20Sopenharmony_ci default_cmode = CMODE_8; 24088c2ecf20Sopenharmony_ci break; 24098c2ecf20Sopenharmony_ci case 15: 24108c2ecf20Sopenharmony_ci case 16: 24118c2ecf20Sopenharmony_ci default_cmode = CMODE_16; 24128c2ecf20Sopenharmony_ci break; 24138c2ecf20Sopenharmony_ci case 24: 24148c2ecf20Sopenharmony_ci case 32: 24158c2ecf20Sopenharmony_ci default_cmode = CMODE_32; 24168c2ecf20Sopenharmony_ci break; 24178c2ecf20Sopenharmony_ci } 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci#endif 24208c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */ 24218c2ecf20Sopenharmony_ci disabled = 1; 24228c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */ 24238c2ecf20Sopenharmony_ci disabled = 0; 24248c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */ 24258c2ecf20Sopenharmony_ci sgram = 1; 24268c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "sdram")) 24278c2ecf20Sopenharmony_ci sgram = 0; 24288c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "memtype:", 8)) 24298c2ecf20Sopenharmony_ci memtype = simple_strtoul(this_opt+8, NULL, 0); 24308c2ecf20Sopenharmony_ci else { 24318c2ecf20Sopenharmony_ci int value = 1; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci if (!strncmp(this_opt, "no", 2)) { 24348c2ecf20Sopenharmony_ci value = 0; 24358c2ecf20Sopenharmony_ci this_opt += 2; 24368c2ecf20Sopenharmony_ci } 24378c2ecf20Sopenharmony_ci if (! strcmp(this_opt, "inverse")) 24388c2ecf20Sopenharmony_ci inverse = value; 24398c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "accel")) 24408c2ecf20Sopenharmony_ci noaccel = !value; 24418c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "pan")) 24428c2ecf20Sopenharmony_ci nopan = !value; 24438c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "pciretry")) 24448c2ecf20Sopenharmony_ci no_pci_retry = !value; 24458c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "vga")) 24468c2ecf20Sopenharmony_ci novga = !value; 24478c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "bios")) 24488c2ecf20Sopenharmony_ci nobios = !value; 24498c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "init")) 24508c2ecf20Sopenharmony_ci noinit = !value; 24518c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "mtrr")) 24528c2ecf20Sopenharmony_ci mtrr = value; 24538c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "inv24")) 24548c2ecf20Sopenharmony_ci inv24 = value; 24558c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "cross4MB")) 24568c2ecf20Sopenharmony_ci cross4MB = value; 24578c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "grayscale")) 24588c2ecf20Sopenharmony_ci grayscale = value; 24598c2ecf20Sopenharmony_ci else if (!strcmp(this_opt, "dfp")) 24608c2ecf20Sopenharmony_ci dfp = value; 24618c2ecf20Sopenharmony_ci else { 24628c2ecf20Sopenharmony_ci strlcpy(videomode, this_opt, sizeof(videomode)); 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci } 24658c2ecf20Sopenharmony_ci } 24668c2ecf20Sopenharmony_ci return 0; 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_cistatic int __initdata initialized = 0; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_cistatic int __init matroxfb_init(void) 24728c2ecf20Sopenharmony_ci{ 24738c2ecf20Sopenharmony_ci char *option = NULL; 24748c2ecf20Sopenharmony_ci int err = 0; 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci DBG(__func__) 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci if (fb_get_options("matroxfb", &option)) 24798c2ecf20Sopenharmony_ci return -ENODEV; 24808c2ecf20Sopenharmony_ci matroxfb_setup(option); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci if (disabled) 24838c2ecf20Sopenharmony_ci return -ENXIO; 24848c2ecf20Sopenharmony_ci if (!initialized) { 24858c2ecf20Sopenharmony_ci initialized = 1; 24868c2ecf20Sopenharmony_ci err = matrox_init(); 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci hotplug = 1; 24898c2ecf20Sopenharmony_ci /* never return failure, user can hotplug matrox later... */ 24908c2ecf20Sopenharmony_ci return err; 24918c2ecf20Sopenharmony_ci} 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_cimodule_init(matroxfb_init); 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci#else 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci/* *************************** init module code **************************** */ 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ciMODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); 25008c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550"); 25018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_cimodule_param(mem, int, 0); 25048c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)"); 25058c2ecf20Sopenharmony_cimodule_param(disabled, int, 0); 25068c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled) (default=0)"); 25078c2ecf20Sopenharmony_cimodule_param(noaccel, int, 0); 25088c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)"); 25098c2ecf20Sopenharmony_cimodule_param(nopan, int, 0); 25108c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)"); 25118c2ecf20Sopenharmony_cimodule_param(no_pci_retry, int, 0); 25128c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)"); 25138c2ecf20Sopenharmony_cimodule_param(novga, int, 0); 25148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)"); 25158c2ecf20Sopenharmony_cimodule_param(nobios, int, 0); 25168c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)"); 25178c2ecf20Sopenharmony_cimodule_param(noinit, int, 0); 25188c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)"); 25198c2ecf20Sopenharmony_cimodule_param(memtype, int, 0); 25208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.rst for explanation) (default=3 for G200, 0 for G400)"); 25218c2ecf20Sopenharmony_cimodule_param(mtrr, int, 0); 25228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)"); 25238c2ecf20Sopenharmony_cimodule_param(sgram, int, 0); 25248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)"); 25258c2ecf20Sopenharmony_cimodule_param(inv24, int, 0); 25268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)"); 25278c2ecf20Sopenharmony_cimodule_param(inverse, int, 0); 25288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)"); 25298c2ecf20Sopenharmony_cimodule_param(dev, int, 0); 25308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)"); 25318c2ecf20Sopenharmony_cimodule_param(vesa, int, 0); 25328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)"); 25338c2ecf20Sopenharmony_cimodule_param(xres, int, 0); 25348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xres, "Horizontal resolution (px), overrides xres from vesa (default=vesa)"); 25358c2ecf20Sopenharmony_cimodule_param(yres, int, 0); 25368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)"); 25378c2ecf20Sopenharmony_cimodule_param(upper, int, 0); 25388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)"); 25398c2ecf20Sopenharmony_cimodule_param(lower, int, 0); 25408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)"); 25418c2ecf20Sopenharmony_cimodule_param(vslen, int, 0); 25428c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)"); 25438c2ecf20Sopenharmony_cimodule_param(left, int, 0); 25448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)"); 25458c2ecf20Sopenharmony_cimodule_param(right, int, 0); 25468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)"); 25478c2ecf20Sopenharmony_cimodule_param(hslen, int, 0); 25488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)"); 25498c2ecf20Sopenharmony_cimodule_param(pixclock, int, 0); 25508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)"); 25518c2ecf20Sopenharmony_cimodule_param(sync, int, 0); 25528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)"); 25538c2ecf20Sopenharmony_cimodule_param(depth, int, 0); 25548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)"); 25558c2ecf20Sopenharmony_cimodule_param(maxclk, int, 0); 25568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz"); 25578c2ecf20Sopenharmony_cimodule_param(fh, int, 0); 25588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz"); 25598c2ecf20Sopenharmony_cimodule_param(fv, int, 0); 25608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n" 25618c2ecf20Sopenharmony_ci"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\""); 25628c2ecf20Sopenharmony_cimodule_param(grayscale, int, 0); 25638c2ecf20Sopenharmony_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)"); 25648c2ecf20Sopenharmony_cimodule_param(cross4MB, int, 0); 25658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)"); 25668c2ecf20Sopenharmony_cimodule_param(dfp, int, 0); 25678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)"); 25688c2ecf20Sopenharmony_cimodule_param(dfp_type, int, 0); 25698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)"); 25708c2ecf20Sopenharmony_cimodule_param_string(outputs, outputs, sizeof(outputs), 0); 25718c2ecf20Sopenharmony_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)"); 25728c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PMAC 25738c2ecf20Sopenharmony_cimodule_param_named(vmode, default_vmode, int, 0); 25748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)"); 25758c2ecf20Sopenharmony_cimodule_param_named(cmode, default_cmode, int, 0); 25768c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)"); 25778c2ecf20Sopenharmony_ci#endif 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ciint __init init_module(void){ 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci DBG(__func__) 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci if (disabled) 25848c2ecf20Sopenharmony_ci return -ENXIO; 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci if (depth == 0) 25878c2ecf20Sopenharmony_ci depth = RSText; 25888c2ecf20Sopenharmony_ci else if (depth == 4) 25898c2ecf20Sopenharmony_ci depth = RS4bpp; 25908c2ecf20Sopenharmony_ci else if (depth == 8) 25918c2ecf20Sopenharmony_ci depth = RS8bpp; 25928c2ecf20Sopenharmony_ci else if (depth == 15) 25938c2ecf20Sopenharmony_ci depth = RS15bpp; 25948c2ecf20Sopenharmony_ci else if (depth == 16) 25958c2ecf20Sopenharmony_ci depth = RS16bpp; 25968c2ecf20Sopenharmony_ci else if (depth == 24) 25978c2ecf20Sopenharmony_ci depth = RS24bpp; 25988c2ecf20Sopenharmony_ci else if (depth == 32) 25998c2ecf20Sopenharmony_ci depth = RS32bpp; 26008c2ecf20Sopenharmony_ci else if (depth != -1) { 26018c2ecf20Sopenharmony_ci printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth); 26028c2ecf20Sopenharmony_ci depth = -1; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci matrox_init(); 26058c2ecf20Sopenharmony_ci /* never return failure; user can hotplug matrox later... */ 26068c2ecf20Sopenharmony_ci return 0; 26078c2ecf20Sopenharmony_ci} 26088c2ecf20Sopenharmony_ci#endif /* MODULE */ 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_cimodule_exit(matrox_done); 26118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(matroxfb_register_driver); 26128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(matroxfb_unregister_driver); 26138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(matroxfb_wait_for_sync); 26148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(matroxfb_enable_irq); 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci/* 26178c2ecf20Sopenharmony_ci * Overrides for Emacs so that we follow Linus's tabbing style. 26188c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 26198c2ecf20Sopenharmony_ci * Local variables: 26208c2ecf20Sopenharmony_ci * c-basic-offset: 8 26218c2ecf20Sopenharmony_ci * End: 26228c2ecf20Sopenharmony_ci */ 26238c2ecf20Sopenharmony_ci 2624