162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2001-2002 Denis Oliver Kropp <dok@directfb.org> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Card specific code is based on XFree86's neomagic driver. 862306a36Sopenharmony_ci * Framebuffer framework code is based on code of cyber2000fb. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General 1162306a36Sopenharmony_ci * Public License. See the file COPYING in the main directory of this 1262306a36Sopenharmony_ci * archive for more details. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * 0.4.1 1662306a36Sopenharmony_ci * - Cosmetic changes (dok) 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * 0.4 1962306a36Sopenharmony_ci * - Toshiba Libretto support, allow modes larger than LCD size if 2062306a36Sopenharmony_ci * LCD is disabled, keep BIOS settings if internal/external display 2162306a36Sopenharmony_ci * haven't been enabled explicitly 2262306a36Sopenharmony_ci * (Thomas J. Moore <dark@mama.indstate.edu>) 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * 0.3.3 2562306a36Sopenharmony_ci * - Porting over to new fbdev api. (jsimmons) 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * 0.3.2 2862306a36Sopenharmony_ci * - got rid of all floating point (dok) 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * 0.3.1 3162306a36Sopenharmony_ci * - added module license (dok) 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * 0.3 3462306a36Sopenharmony_ci * - hardware accelerated clear and move for 2200 and above (dok) 3562306a36Sopenharmony_ci * - maximum allowed dotclock is handled now (dok) 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * 0.2.1 3862306a36Sopenharmony_ci * - correct panning after X usage (dok) 3962306a36Sopenharmony_ci * - added module and kernel parameters (dok) 4062306a36Sopenharmony_ci * - no stretching if external display is enabled (dok) 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * 0.2 4362306a36Sopenharmony_ci * - initial version (dok) 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * TODO 4762306a36Sopenharmony_ci * - ioctl for internal/external switching 4862306a36Sopenharmony_ci * - blanking 4962306a36Sopenharmony_ci * - 32bit depth support, maybe impossible 5062306a36Sopenharmony_ci * - disable pan-on-sync, need specs 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * BUGS 5362306a36Sopenharmony_ci * - white margin on bootup like with tdfxfb (colormap problem?) 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#include <linux/aperture.h> 5862306a36Sopenharmony_ci#include <linux/module.h> 5962306a36Sopenharmony_ci#include <linux/kernel.h> 6062306a36Sopenharmony_ci#include <linux/errno.h> 6162306a36Sopenharmony_ci#include <linux/string.h> 6262306a36Sopenharmony_ci#include <linux/mm.h> 6362306a36Sopenharmony_ci#include <linux/slab.h> 6462306a36Sopenharmony_ci#include <linux/delay.h> 6562306a36Sopenharmony_ci#include <linux/fb.h> 6662306a36Sopenharmony_ci#include <linux/pci.h> 6762306a36Sopenharmony_ci#include <linux/init.h> 6862306a36Sopenharmony_ci#ifdef CONFIG_TOSHIBA 6962306a36Sopenharmony_ci#include <linux/toshiba.h> 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#include <asm/io.h> 7362306a36Sopenharmony_ci#include <asm/irq.h> 7462306a36Sopenharmony_ci#include <video/vga.h> 7562306a36Sopenharmony_ci#include <video/neomagic.h> 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define NEOFB_VERSION "0.4.2" 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic bool internal; 8262306a36Sopenharmony_cistatic bool external; 8362306a36Sopenharmony_cistatic bool libretto; 8462306a36Sopenharmony_cistatic bool nostretch; 8562306a36Sopenharmony_cistatic bool nopciburst; 8662306a36Sopenharmony_cistatic char *mode_option = NULL; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#ifdef MODULE 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciMODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@convergence.de>"); 9162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 9262306a36Sopenharmony_ciMODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips"); 9362306a36Sopenharmony_cimodule_param(internal, bool, 0); 9462306a36Sopenharmony_ciMODULE_PARM_DESC(internal, "Enable output on internal LCD Display."); 9562306a36Sopenharmony_cimodule_param(external, bool, 0); 9662306a36Sopenharmony_ciMODULE_PARM_DESC(external, "Enable output on external CRT."); 9762306a36Sopenharmony_cimodule_param(libretto, bool, 0); 9862306a36Sopenharmony_ciMODULE_PARM_DESC(libretto, "Force Libretto 100/110 800x480 LCD."); 9962306a36Sopenharmony_cimodule_param(nostretch, bool, 0); 10062306a36Sopenharmony_ciMODULE_PARM_DESC(nostretch, 10162306a36Sopenharmony_ci "Disable stretching of modes smaller than LCD."); 10262306a36Sopenharmony_cimodule_param(nopciburst, bool, 0); 10362306a36Sopenharmony_ciMODULE_PARM_DESC(nopciburst, "Disable PCI burst mode."); 10462306a36Sopenharmony_cimodule_param(mode_option, charp, 0); 10562306a36Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Preferred video mode ('640x480-8@60', etc)"); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#endif 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic biosMode bios8[] = { 11362306a36Sopenharmony_ci {320, 240, 0x40}, 11462306a36Sopenharmony_ci {300, 400, 0x42}, 11562306a36Sopenharmony_ci {640, 400, 0x20}, 11662306a36Sopenharmony_ci {640, 480, 0x21}, 11762306a36Sopenharmony_ci {800, 600, 0x23}, 11862306a36Sopenharmony_ci {1024, 768, 0x25}, 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic biosMode bios16[] = { 12262306a36Sopenharmony_ci {320, 200, 0x2e}, 12362306a36Sopenharmony_ci {320, 240, 0x41}, 12462306a36Sopenharmony_ci {300, 400, 0x43}, 12562306a36Sopenharmony_ci {640, 480, 0x31}, 12662306a36Sopenharmony_ci {800, 600, 0x34}, 12762306a36Sopenharmony_ci {1024, 768, 0x37}, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic biosMode bios24[] = { 13162306a36Sopenharmony_ci {640, 480, 0x32}, 13262306a36Sopenharmony_ci {800, 600, 0x35}, 13362306a36Sopenharmony_ci {1024, 768, 0x38} 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET 13762306a36Sopenharmony_ci/* FIXME: guessed values, wrong */ 13862306a36Sopenharmony_cistatic biosMode bios32[] = { 13962306a36Sopenharmony_ci {640, 480, 0x33}, 14062306a36Sopenharmony_ci {800, 600, 0x36}, 14162306a36Sopenharmony_ci {1024, 768, 0x39} 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci#endif 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic inline void write_le32(int regindex, u32 val, const struct neofb_par *par) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci writel(val, par->neo2200 + par->cursorOff + regindex); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int neoFindMode(int xres, int yres, int depth) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci int xres_s; 15362306a36Sopenharmony_ci int i, size; 15462306a36Sopenharmony_ci biosMode *mode; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci switch (depth) { 15762306a36Sopenharmony_ci case 8: 15862306a36Sopenharmony_ci size = ARRAY_SIZE(bios8); 15962306a36Sopenharmony_ci mode = bios8; 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci case 16: 16262306a36Sopenharmony_ci size = ARRAY_SIZE(bios16); 16362306a36Sopenharmony_ci mode = bios16; 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci case 24: 16662306a36Sopenharmony_ci size = ARRAY_SIZE(bios24); 16762306a36Sopenharmony_ci mode = bios24; 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET 17062306a36Sopenharmony_ci case 32: 17162306a36Sopenharmony_ci size = ARRAY_SIZE(bios32); 17262306a36Sopenharmony_ci mode = bios32; 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci#endif 17562306a36Sopenharmony_ci default: 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci for (i = 0; i < size; i++) { 18062306a36Sopenharmony_ci if (xres <= mode[i].x_res) { 18162306a36Sopenharmony_ci xres_s = mode[i].x_res; 18262306a36Sopenharmony_ci for (; i < size; i++) { 18362306a36Sopenharmony_ci if (mode[i].x_res != xres_s) 18462306a36Sopenharmony_ci return mode[i - 1].mode; 18562306a36Sopenharmony_ci if (yres <= mode[i].y_res) 18662306a36Sopenharmony_ci return mode[i].mode; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci return mode[size - 1].mode; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* 19462306a36Sopenharmony_ci * neoCalcVCLK -- 19562306a36Sopenharmony_ci * 19662306a36Sopenharmony_ci * Determine the closest clock frequency to the one requested. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci#define MAX_N 127 19962306a36Sopenharmony_ci#define MAX_D 31 20062306a36Sopenharmony_ci#define MAX_F 1 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void neoCalcVCLK(const struct fb_info *info, 20362306a36Sopenharmony_ci struct neofb_par *par, long freq) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci int n, d, f; 20662306a36Sopenharmony_ci int n_best = 0, d_best = 0, f_best = 0; 20762306a36Sopenharmony_ci long f_best_diff = 0x7ffff; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci for (f = 0; f <= MAX_F; f++) 21062306a36Sopenharmony_ci for (d = 0; d <= MAX_D; d++) 21162306a36Sopenharmony_ci for (n = 0; n <= MAX_N; n++) { 21262306a36Sopenharmony_ci long f_out; 21362306a36Sopenharmony_ci long f_diff; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci f_out = ((14318 * (n + 1)) / (d + 1)) >> f; 21662306a36Sopenharmony_ci f_diff = abs(f_out - freq); 21762306a36Sopenharmony_ci if (f_diff <= f_best_diff) { 21862306a36Sopenharmony_ci f_best_diff = f_diff; 21962306a36Sopenharmony_ci n_best = n; 22062306a36Sopenharmony_ci d_best = d; 22162306a36Sopenharmony_ci f_best = f; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci if (f_out > freq) 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 || 22862306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 || 22962306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 || 23062306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) { 23162306a36Sopenharmony_ci /* NOT_DONE: We are trying the full range of the 2200 clock. 23262306a36Sopenharmony_ci We should be able to try n up to 2047 */ 23362306a36Sopenharmony_ci par->VCLK3NumeratorLow = n_best; 23462306a36Sopenharmony_ci par->VCLK3NumeratorHigh = (f_best << 7); 23562306a36Sopenharmony_ci } else 23662306a36Sopenharmony_ci par->VCLK3NumeratorLow = n_best | (f_best << 7); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci par->VCLK3Denominator = d_best; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci#ifdef NEOFB_DEBUG 24162306a36Sopenharmony_ci printk(KERN_DEBUG "neoVCLK: f:%ld NumLow=%d NumHi=%d Den=%d Df=%ld\n", 24262306a36Sopenharmony_ci freq, 24362306a36Sopenharmony_ci par->VCLK3NumeratorLow, 24462306a36Sopenharmony_ci par->VCLK3NumeratorHigh, 24562306a36Sopenharmony_ci par->VCLK3Denominator, f_best_diff); 24662306a36Sopenharmony_ci#endif 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/* 25062306a36Sopenharmony_ci * vgaHWInit -- 25162306a36Sopenharmony_ci * Handle the initialization, etc. of a screen. 25262306a36Sopenharmony_ci * Return FALSE on failure. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int vgaHWInit(const struct fb_var_screeninfo *var, 25662306a36Sopenharmony_ci struct neofb_par *par) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci int hsync_end = var->xres + var->right_margin + var->hsync_len; 25962306a36Sopenharmony_ci int htotal = (hsync_end + var->left_margin) >> 3; 26062306a36Sopenharmony_ci int vsync_start = var->yres + var->lower_margin; 26162306a36Sopenharmony_ci int vsync_end = vsync_start + var->vsync_len; 26262306a36Sopenharmony_ci int vtotal = vsync_end + var->upper_margin; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci par->MiscOutReg = 0x23; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) 26762306a36Sopenharmony_ci par->MiscOutReg |= 0x40; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) 27062306a36Sopenharmony_ci par->MiscOutReg |= 0x80; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* 27362306a36Sopenharmony_ci * Time Sequencer 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_ci par->Sequencer[0] = 0x00; 27662306a36Sopenharmony_ci par->Sequencer[1] = 0x01; 27762306a36Sopenharmony_ci par->Sequencer[2] = 0x0F; 27862306a36Sopenharmony_ci par->Sequencer[3] = 0x00; /* Font select */ 27962306a36Sopenharmony_ci par->Sequencer[4] = 0x0E; /* Misc */ 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * CRTC Controller 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci par->CRTC[0] = htotal - 5; 28562306a36Sopenharmony_ci par->CRTC[1] = (var->xres >> 3) - 1; 28662306a36Sopenharmony_ci par->CRTC[2] = (var->xres >> 3) - 1; 28762306a36Sopenharmony_ci par->CRTC[3] = ((htotal - 1) & 0x1F) | 0x80; 28862306a36Sopenharmony_ci par->CRTC[4] = ((var->xres + var->right_margin) >> 3); 28962306a36Sopenharmony_ci par->CRTC[5] = (((htotal - 1) & 0x20) << 2) 29062306a36Sopenharmony_ci | (((hsync_end >> 3)) & 0x1F); 29162306a36Sopenharmony_ci par->CRTC[6] = (vtotal - 2) & 0xFF; 29262306a36Sopenharmony_ci par->CRTC[7] = (((vtotal - 2) & 0x100) >> 8) 29362306a36Sopenharmony_ci | (((var->yres - 1) & 0x100) >> 7) 29462306a36Sopenharmony_ci | ((vsync_start & 0x100) >> 6) 29562306a36Sopenharmony_ci | (((var->yres - 1) & 0x100) >> 5) 29662306a36Sopenharmony_ci | 0x10 | (((vtotal - 2) & 0x200) >> 4) 29762306a36Sopenharmony_ci | (((var->yres - 1) & 0x200) >> 3) 29862306a36Sopenharmony_ci | ((vsync_start & 0x200) >> 2); 29962306a36Sopenharmony_ci par->CRTC[8] = 0x00; 30062306a36Sopenharmony_ci par->CRTC[9] = (((var->yres - 1) & 0x200) >> 4) | 0x40; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (var->vmode & FB_VMODE_DOUBLE) 30362306a36Sopenharmony_ci par->CRTC[9] |= 0x80; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci par->CRTC[10] = 0x00; 30662306a36Sopenharmony_ci par->CRTC[11] = 0x00; 30762306a36Sopenharmony_ci par->CRTC[12] = 0x00; 30862306a36Sopenharmony_ci par->CRTC[13] = 0x00; 30962306a36Sopenharmony_ci par->CRTC[14] = 0x00; 31062306a36Sopenharmony_ci par->CRTC[15] = 0x00; 31162306a36Sopenharmony_ci par->CRTC[16] = vsync_start & 0xFF; 31262306a36Sopenharmony_ci par->CRTC[17] = (vsync_end & 0x0F) | 0x20; 31362306a36Sopenharmony_ci par->CRTC[18] = (var->yres - 1) & 0xFF; 31462306a36Sopenharmony_ci par->CRTC[19] = var->xres_virtual >> 4; 31562306a36Sopenharmony_ci par->CRTC[20] = 0x00; 31662306a36Sopenharmony_ci par->CRTC[21] = (var->yres - 1) & 0xFF; 31762306a36Sopenharmony_ci par->CRTC[22] = (vtotal - 1) & 0xFF; 31862306a36Sopenharmony_ci par->CRTC[23] = 0xC3; 31962306a36Sopenharmony_ci par->CRTC[24] = 0xFF; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * are these unnecessary? 32362306a36Sopenharmony_ci * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); 32462306a36Sopenharmony_ci * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO); 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* 32862306a36Sopenharmony_ci * Graphics Display Controller 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci par->Graphics[0] = 0x00; 33162306a36Sopenharmony_ci par->Graphics[1] = 0x00; 33262306a36Sopenharmony_ci par->Graphics[2] = 0x00; 33362306a36Sopenharmony_ci par->Graphics[3] = 0x00; 33462306a36Sopenharmony_ci par->Graphics[4] = 0x00; 33562306a36Sopenharmony_ci par->Graphics[5] = 0x40; 33662306a36Sopenharmony_ci par->Graphics[6] = 0x05; /* only map 64k VGA memory !!!! */ 33762306a36Sopenharmony_ci par->Graphics[7] = 0x0F; 33862306a36Sopenharmony_ci par->Graphics[8] = 0xFF; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci par->Attribute[0] = 0x00; /* standard colormap translation */ 34262306a36Sopenharmony_ci par->Attribute[1] = 0x01; 34362306a36Sopenharmony_ci par->Attribute[2] = 0x02; 34462306a36Sopenharmony_ci par->Attribute[3] = 0x03; 34562306a36Sopenharmony_ci par->Attribute[4] = 0x04; 34662306a36Sopenharmony_ci par->Attribute[5] = 0x05; 34762306a36Sopenharmony_ci par->Attribute[6] = 0x06; 34862306a36Sopenharmony_ci par->Attribute[7] = 0x07; 34962306a36Sopenharmony_ci par->Attribute[8] = 0x08; 35062306a36Sopenharmony_ci par->Attribute[9] = 0x09; 35162306a36Sopenharmony_ci par->Attribute[10] = 0x0A; 35262306a36Sopenharmony_ci par->Attribute[11] = 0x0B; 35362306a36Sopenharmony_ci par->Attribute[12] = 0x0C; 35462306a36Sopenharmony_ci par->Attribute[13] = 0x0D; 35562306a36Sopenharmony_ci par->Attribute[14] = 0x0E; 35662306a36Sopenharmony_ci par->Attribute[15] = 0x0F; 35762306a36Sopenharmony_ci par->Attribute[16] = 0x41; 35862306a36Sopenharmony_ci par->Attribute[17] = 0xFF; 35962306a36Sopenharmony_ci par->Attribute[18] = 0x0F; 36062306a36Sopenharmony_ci par->Attribute[19] = 0x00; 36162306a36Sopenharmony_ci par->Attribute[20] = 0x00; 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic void vgaHWLock(struct vgastate *state) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci /* Protect CRTC[0-7] */ 36862306a36Sopenharmony_ci vga_wcrt(state->vgabase, 0x11, vga_rcrt(state->vgabase, 0x11) | 0x80); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic void vgaHWUnlock(void) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci /* Unprotect CRTC[0-7] */ 37462306a36Sopenharmony_ci vga_wcrt(NULL, 0x11, vga_rcrt(NULL, 0x11) & ~0x80); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic void neoLock(struct vgastate *state) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci vga_wgfx(state->vgabase, 0x09, 0x00); 38062306a36Sopenharmony_ci vgaHWLock(state); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic void neoUnlock(void) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci vgaHWUnlock(); 38662306a36Sopenharmony_ci vga_wgfx(NULL, 0x09, 0x26); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci/* 39062306a36Sopenharmony_ci * VGA Palette management 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_cistatic int paletteEnabled = 0; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic inline void VGAenablePalette(void) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci vga_r(NULL, VGA_IS1_RC); 39762306a36Sopenharmony_ci vga_w(NULL, VGA_ATT_W, 0x00); 39862306a36Sopenharmony_ci paletteEnabled = 1; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic inline void VGAdisablePalette(void) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci vga_r(NULL, VGA_IS1_RC); 40462306a36Sopenharmony_ci vga_w(NULL, VGA_ATT_W, 0x20); 40562306a36Sopenharmony_ci paletteEnabled = 0; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic inline void VGAwATTR(u8 index, u8 value) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci if (paletteEnabled) 41162306a36Sopenharmony_ci index &= ~0x20; 41262306a36Sopenharmony_ci else 41362306a36Sopenharmony_ci index |= 0x20; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci vga_r(NULL, VGA_IS1_RC); 41662306a36Sopenharmony_ci vga_wattr(NULL, index, value); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void vgaHWProtect(int on) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci unsigned char tmp; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci tmp = vga_rseq(NULL, 0x01); 42462306a36Sopenharmony_ci if (on) { 42562306a36Sopenharmony_ci /* 42662306a36Sopenharmony_ci * Turn off screen and disable sequencer. 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci vga_wseq(NULL, 0x00, 0x01); /* Synchronous Reset */ 42962306a36Sopenharmony_ci vga_wseq(NULL, 0x01, tmp | 0x20); /* disable the display */ 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci VGAenablePalette(); 43262306a36Sopenharmony_ci } else { 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * Reenable sequencer, then turn on screen. 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_ci vga_wseq(NULL, 0x01, tmp & ~0x20); /* reenable display */ 43762306a36Sopenharmony_ci vga_wseq(NULL, 0x00, 0x03); /* clear synchronousreset */ 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci VGAdisablePalette(); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic void vgaHWRestore(const struct fb_info *info, 44462306a36Sopenharmony_ci const struct neofb_par *par) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci int i; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci vga_w(NULL, VGA_MIS_W, par->MiscOutReg); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci for (i = 1; i < 5; i++) 45162306a36Sopenharmony_ci vga_wseq(NULL, i, par->Sequencer[i]); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */ 45462306a36Sopenharmony_ci vga_wcrt(NULL, 17, par->CRTC[17] & ~0x80); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci for (i = 0; i < 25; i++) 45762306a36Sopenharmony_ci vga_wcrt(NULL, i, par->CRTC[i]); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci for (i = 0; i < 9; i++) 46062306a36Sopenharmony_ci vga_wgfx(NULL, i, par->Graphics[i]); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci VGAenablePalette(); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci for (i = 0; i < 21; i++) 46562306a36Sopenharmony_ci VGAwATTR(i, par->Attribute[i]); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci VGAdisablePalette(); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* -------------------- Hardware specific routines ------------------------- */ 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/* 47462306a36Sopenharmony_ci * Hardware Acceleration for Neo2200+ 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_cistatic inline int neo2200_sync(struct fb_info *info) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct neofb_par *par = info->par; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci while (readl(&par->neo2200->bltStat) & 1) 48162306a36Sopenharmony_ci cpu_relax(); 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic inline void neo2200_wait_fifo(struct fb_info *info, 48662306a36Sopenharmony_ci int requested_fifo_space) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci // ndev->neo.waitfifo_calls++; 48962306a36Sopenharmony_ci // ndev->neo.waitfifo_sum += requested_fifo_space; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* FIXME: does not work 49262306a36Sopenharmony_ci if (neo_fifo_space < requested_fifo_space) 49362306a36Sopenharmony_ci { 49462306a36Sopenharmony_ci neo_fifo_waitcycles++; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci while (1) 49762306a36Sopenharmony_ci { 49862306a36Sopenharmony_ci neo_fifo_space = (neo2200->bltStat >> 8); 49962306a36Sopenharmony_ci if (neo_fifo_space >= requested_fifo_space) 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci else 50462306a36Sopenharmony_ci { 50562306a36Sopenharmony_ci neo_fifo_cache_hits++; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci neo_fifo_space -= requested_fifo_space; 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci neo2200_sync(info); 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic inline void neo2200_accel_init(struct fb_info *info, 51562306a36Sopenharmony_ci struct fb_var_screeninfo *var) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct neofb_par *par = info->par; 51862306a36Sopenharmony_ci Neo2200 __iomem *neo2200 = par->neo2200; 51962306a36Sopenharmony_ci u32 bltMod, pitch; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci neo2200_sync(info); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci switch (var->bits_per_pixel) { 52462306a36Sopenharmony_ci case 8: 52562306a36Sopenharmony_ci bltMod = NEO_MODE1_DEPTH8; 52662306a36Sopenharmony_ci pitch = var->xres_virtual; 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci case 15: 52962306a36Sopenharmony_ci case 16: 53062306a36Sopenharmony_ci bltMod = NEO_MODE1_DEPTH16; 53162306a36Sopenharmony_ci pitch = var->xres_virtual * 2; 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci case 24: 53462306a36Sopenharmony_ci bltMod = NEO_MODE1_DEPTH24; 53562306a36Sopenharmony_ci pitch = var->xres_virtual * 3; 53662306a36Sopenharmony_ci break; 53762306a36Sopenharmony_ci default: 53862306a36Sopenharmony_ci printk(KERN_ERR 53962306a36Sopenharmony_ci "neofb: neo2200_accel_init: unexpected bits per pixel!\n"); 54062306a36Sopenharmony_ci return; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci writel(bltMod << 16, &neo2200->bltStat); 54462306a36Sopenharmony_ci writel((pitch << 16) | pitch, &neo2200->pitch); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic int 55062306a36Sopenharmony_cineofb_open(struct fb_info *info, int user) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct neofb_par *par = info->par; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (!par->ref_count) { 55562306a36Sopenharmony_ci memset(&par->state, 0, sizeof(struct vgastate)); 55662306a36Sopenharmony_ci par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS; 55762306a36Sopenharmony_ci save_vga(&par->state); 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci par->ref_count++; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic int 56562306a36Sopenharmony_cineofb_release(struct fb_info *info, int user) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct neofb_par *par = info->par; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (!par->ref_count) 57062306a36Sopenharmony_ci return -EINVAL; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (par->ref_count == 1) { 57362306a36Sopenharmony_ci restore_vga(&par->state); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci par->ref_count--; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int 58162306a36Sopenharmony_cineofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct neofb_par *par = info->par; 58462306a36Sopenharmony_ci int memlen, vramlen; 58562306a36Sopenharmony_ci int mode_ok = 0; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci DBG("neofb_check_var"); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (!var->pixclock || PICOS2KHZ(var->pixclock) > par->maxClock) 59062306a36Sopenharmony_ci return -EINVAL; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* Is the mode larger than the LCD panel? */ 59362306a36Sopenharmony_ci if (par->internal_display && 59462306a36Sopenharmony_ci ((var->xres > par->NeoPanelWidth) || 59562306a36Sopenharmony_ci (var->yres > par->NeoPanelHeight))) { 59662306a36Sopenharmony_ci printk(KERN_INFO 59762306a36Sopenharmony_ci "Mode (%dx%d) larger than the LCD panel (%dx%d)\n", 59862306a36Sopenharmony_ci var->xres, var->yres, par->NeoPanelWidth, 59962306a36Sopenharmony_ci par->NeoPanelHeight); 60062306a36Sopenharmony_ci return -EINVAL; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* Is the mode one of the acceptable sizes? */ 60462306a36Sopenharmony_ci if (!par->internal_display) 60562306a36Sopenharmony_ci mode_ok = 1; 60662306a36Sopenharmony_ci else { 60762306a36Sopenharmony_ci switch (var->xres) { 60862306a36Sopenharmony_ci case 1280: 60962306a36Sopenharmony_ci if (var->yres == 1024) 61062306a36Sopenharmony_ci mode_ok = 1; 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci case 1024: 61362306a36Sopenharmony_ci if (var->yres == 768) 61462306a36Sopenharmony_ci mode_ok = 1; 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci case 800: 61762306a36Sopenharmony_ci if (var->yres == (par->libretto ? 480 : 600)) 61862306a36Sopenharmony_ci mode_ok = 1; 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci case 640: 62162306a36Sopenharmony_ci if (var->yres == 480) 62262306a36Sopenharmony_ci mode_ok = 1; 62362306a36Sopenharmony_ci break; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (!mode_ok) { 62862306a36Sopenharmony_ci printk(KERN_INFO 62962306a36Sopenharmony_ci "Mode (%dx%d) won't display properly on LCD\n", 63062306a36Sopenharmony_ci var->xres, var->yres); 63162306a36Sopenharmony_ci return -EINVAL; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci var->red.msb_right = 0; 63562306a36Sopenharmony_ci var->green.msb_right = 0; 63662306a36Sopenharmony_ci var->blue.msb_right = 0; 63762306a36Sopenharmony_ci var->transp.msb_right = 0; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci var->transp.offset = 0; 64062306a36Sopenharmony_ci var->transp.length = 0; 64162306a36Sopenharmony_ci switch (var->bits_per_pixel) { 64262306a36Sopenharmony_ci case 8: /* PSEUDOCOLOUR, 256 */ 64362306a36Sopenharmony_ci var->red.offset = 0; 64462306a36Sopenharmony_ci var->red.length = 8; 64562306a36Sopenharmony_ci var->green.offset = 0; 64662306a36Sopenharmony_ci var->green.length = 8; 64762306a36Sopenharmony_ci var->blue.offset = 0; 64862306a36Sopenharmony_ci var->blue.length = 8; 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci case 16: /* DIRECTCOLOUR, 64k */ 65262306a36Sopenharmony_ci var->red.offset = 11; 65362306a36Sopenharmony_ci var->red.length = 5; 65462306a36Sopenharmony_ci var->green.offset = 5; 65562306a36Sopenharmony_ci var->green.length = 6; 65662306a36Sopenharmony_ci var->blue.offset = 0; 65762306a36Sopenharmony_ci var->blue.length = 5; 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci case 24: /* TRUECOLOUR, 16m */ 66162306a36Sopenharmony_ci var->red.offset = 16; 66262306a36Sopenharmony_ci var->red.length = 8; 66362306a36Sopenharmony_ci var->green.offset = 8; 66462306a36Sopenharmony_ci var->green.length = 8; 66562306a36Sopenharmony_ci var->blue.offset = 0; 66662306a36Sopenharmony_ci var->blue.length = 8; 66762306a36Sopenharmony_ci break; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET 67062306a36Sopenharmony_ci case 32: /* TRUECOLOUR, 16m */ 67162306a36Sopenharmony_ci var->transp.offset = 24; 67262306a36Sopenharmony_ci var->transp.length = 8; 67362306a36Sopenharmony_ci var->red.offset = 16; 67462306a36Sopenharmony_ci var->red.length = 8; 67562306a36Sopenharmony_ci var->green.offset = 8; 67662306a36Sopenharmony_ci var->green.length = 8; 67762306a36Sopenharmony_ci var->blue.offset = 0; 67862306a36Sopenharmony_ci var->blue.length = 8; 67962306a36Sopenharmony_ci break; 68062306a36Sopenharmony_ci#endif 68162306a36Sopenharmony_ci default: 68262306a36Sopenharmony_ci printk(KERN_WARNING "neofb: no support for %dbpp\n", 68362306a36Sopenharmony_ci var->bits_per_pixel); 68462306a36Sopenharmony_ci return -EINVAL; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci vramlen = info->fix.smem_len; 68862306a36Sopenharmony_ci if (vramlen > 4 * 1024 * 1024) 68962306a36Sopenharmony_ci vramlen = 4 * 1024 * 1024; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (var->xres_virtual < var->xres) 69262306a36Sopenharmony_ci var->xres_virtual = var->xres; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual >> 3; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (memlen > vramlen) { 69762306a36Sopenharmony_ci var->yres_virtual = vramlen * 8 / (var->xres_virtual * 69862306a36Sopenharmony_ci var->bits_per_pixel); 69962306a36Sopenharmony_ci memlen = var->xres_virtual * var->bits_per_pixel * 70062306a36Sopenharmony_ci var->yres_virtual / 8; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* we must round yres/xres down, we already rounded y/xres_virtual up 70462306a36Sopenharmony_ci if it was possible. We should return -EINVAL, but I disagree */ 70562306a36Sopenharmony_ci if (var->yres_virtual < var->yres) 70662306a36Sopenharmony_ci var->yres = var->yres_virtual; 70762306a36Sopenharmony_ci if (var->xoffset + var->xres > var->xres_virtual) 70862306a36Sopenharmony_ci var->xoffset = var->xres_virtual - var->xres; 70962306a36Sopenharmony_ci if (var->yoffset + var->yres > var->yres_virtual) 71062306a36Sopenharmony_ci var->yoffset = var->yres_virtual - var->yres; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci var->nonstd = 0; 71362306a36Sopenharmony_ci var->height = -1; 71462306a36Sopenharmony_ci var->width = -1; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (var->bits_per_pixel >= 24 || !par->neo2200) 71762306a36Sopenharmony_ci var->accel_flags &= ~FB_ACCELF_TEXT; 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic int neofb_set_par(struct fb_info *info) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct neofb_par *par = info->par; 72462306a36Sopenharmony_ci unsigned char temp; 72562306a36Sopenharmony_ci int i, clock_hi = 0; 72662306a36Sopenharmony_ci int lcd_stretch; 72762306a36Sopenharmony_ci int hoffset, voffset; 72862306a36Sopenharmony_ci int vsync_start, vtotal; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci DBG("neofb_set_par"); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci neoUnlock(); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci vgaHWProtect(1); /* Blank the screen */ 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci vsync_start = info->var.yres + info->var.lower_margin; 73762306a36Sopenharmony_ci vtotal = vsync_start + info->var.vsync_len + info->var.upper_margin; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* 74062306a36Sopenharmony_ci * This will allocate the datastructure and initialize all of the 74162306a36Sopenharmony_ci * generic VGA registers. 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (vgaHWInit(&info->var, par)) 74562306a36Sopenharmony_ci return -EINVAL; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci /* 74862306a36Sopenharmony_ci * The default value assigned by vgaHW.c is 0x41, but this does 74962306a36Sopenharmony_ci * not work for NeoMagic. 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_ci par->Attribute[16] = 0x01; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci switch (info->var.bits_per_pixel) { 75462306a36Sopenharmony_ci case 8: 75562306a36Sopenharmony_ci par->CRTC[0x13] = info->var.xres_virtual >> 3; 75662306a36Sopenharmony_ci par->ExtCRTOffset = info->var.xres_virtual >> 11; 75762306a36Sopenharmony_ci par->ExtColorModeSelect = 0x11; 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci case 16: 76062306a36Sopenharmony_ci par->CRTC[0x13] = info->var.xres_virtual >> 2; 76162306a36Sopenharmony_ci par->ExtCRTOffset = info->var.xres_virtual >> 10; 76262306a36Sopenharmony_ci par->ExtColorModeSelect = 0x13; 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci case 24: 76562306a36Sopenharmony_ci par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3; 76662306a36Sopenharmony_ci par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11; 76762306a36Sopenharmony_ci par->ExtColorModeSelect = 0x14; 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET 77062306a36Sopenharmony_ci case 32: /* FIXME: guessed values */ 77162306a36Sopenharmony_ci par->CRTC[0x13] = info->var.xres_virtual >> 1; 77262306a36Sopenharmony_ci par->ExtCRTOffset = info->var.xres_virtual >> 9; 77362306a36Sopenharmony_ci par->ExtColorModeSelect = 0x15; 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci#endif 77662306a36Sopenharmony_ci default: 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci par->ExtCRTDispAddr = 0x10; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* Vertical Extension */ 78362306a36Sopenharmony_ci par->VerticalExt = (((vtotal - 2) & 0x400) >> 10) 78462306a36Sopenharmony_ci | (((info->var.yres - 1) & 0x400) >> 9) 78562306a36Sopenharmony_ci | (((vsync_start) & 0x400) >> 8) 78662306a36Sopenharmony_ci | (((vsync_start) & 0x400) >> 7); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* Fast write bursts on unless disabled. */ 78962306a36Sopenharmony_ci if (par->pci_burst) 79062306a36Sopenharmony_ci par->SysIfaceCntl1 = 0x30; 79162306a36Sopenharmony_ci else 79262306a36Sopenharmony_ci par->SysIfaceCntl1 = 0x00; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */ 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci /* Initialize: by default, we want display config register to be read */ 79762306a36Sopenharmony_ci par->PanelDispCntlRegRead = 1; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* Enable any user specified display devices. */ 80062306a36Sopenharmony_ci par->PanelDispCntlReg1 = 0x00; 80162306a36Sopenharmony_ci if (par->internal_display) 80262306a36Sopenharmony_ci par->PanelDispCntlReg1 |= 0x02; 80362306a36Sopenharmony_ci if (par->external_display) 80462306a36Sopenharmony_ci par->PanelDispCntlReg1 |= 0x01; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* If the user did not specify any display devices, then... */ 80762306a36Sopenharmony_ci if (par->PanelDispCntlReg1 == 0x00) { 80862306a36Sopenharmony_ci /* Default to internal (i.e., LCD) only. */ 80962306a36Sopenharmony_ci par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* If we are using a fixed mode, then tell the chip we are. */ 81362306a36Sopenharmony_ci switch (info->var.xres) { 81462306a36Sopenharmony_ci case 1280: 81562306a36Sopenharmony_ci par->PanelDispCntlReg1 |= 0x60; 81662306a36Sopenharmony_ci break; 81762306a36Sopenharmony_ci case 1024: 81862306a36Sopenharmony_ci par->PanelDispCntlReg1 |= 0x40; 81962306a36Sopenharmony_ci break; 82062306a36Sopenharmony_ci case 800: 82162306a36Sopenharmony_ci par->PanelDispCntlReg1 |= 0x20; 82262306a36Sopenharmony_ci break; 82362306a36Sopenharmony_ci case 640: 82462306a36Sopenharmony_ci default: 82562306a36Sopenharmony_ci break; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* Setup shadow register locking. */ 82962306a36Sopenharmony_ci switch (par->PanelDispCntlReg1 & 0x03) { 83062306a36Sopenharmony_ci case 0x01: /* External CRT only mode: */ 83162306a36Sopenharmony_ci par->GeneralLockReg = 0x00; 83262306a36Sopenharmony_ci /* We need to program the VCLK for external display only mode. */ 83362306a36Sopenharmony_ci par->ProgramVCLK = 1; 83462306a36Sopenharmony_ci break; 83562306a36Sopenharmony_ci case 0x02: /* Internal LCD only mode: */ 83662306a36Sopenharmony_ci case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */ 83762306a36Sopenharmony_ci par->GeneralLockReg = 0x01; 83862306a36Sopenharmony_ci /* Don't program the VCLK when using the LCD. */ 83962306a36Sopenharmony_ci par->ProgramVCLK = 0; 84062306a36Sopenharmony_ci break; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* 84462306a36Sopenharmony_ci * If the screen is to be stretched, turn on stretching for the 84562306a36Sopenharmony_ci * various modes. 84662306a36Sopenharmony_ci * 84762306a36Sopenharmony_ci * OPTION_LCD_STRETCH means stretching should be turned off! 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_ci par->PanelDispCntlReg2 = 0x00; 85062306a36Sopenharmony_ci par->PanelDispCntlReg3 = 0x00; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) && /* LCD only */ 85362306a36Sopenharmony_ci (info->var.xres != par->NeoPanelWidth)) { 85462306a36Sopenharmony_ci switch (info->var.xres) { 85562306a36Sopenharmony_ci case 320: /* Needs testing. KEM -- 24 May 98 */ 85662306a36Sopenharmony_ci case 400: /* Needs testing. KEM -- 24 May 98 */ 85762306a36Sopenharmony_ci case 640: 85862306a36Sopenharmony_ci case 800: 85962306a36Sopenharmony_ci case 1024: 86062306a36Sopenharmony_ci lcd_stretch = 1; 86162306a36Sopenharmony_ci par->PanelDispCntlReg2 |= 0xC6; 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci default: 86462306a36Sopenharmony_ci lcd_stretch = 0; 86562306a36Sopenharmony_ci /* No stretching in these modes. */ 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci } else 86862306a36Sopenharmony_ci lcd_stretch = 0; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* 87162306a36Sopenharmony_ci * If the screen is to be centerd, turn on the centering for the 87262306a36Sopenharmony_ci * various modes. 87362306a36Sopenharmony_ci */ 87462306a36Sopenharmony_ci par->PanelVertCenterReg1 = 0x00; 87562306a36Sopenharmony_ci par->PanelVertCenterReg2 = 0x00; 87662306a36Sopenharmony_ci par->PanelVertCenterReg3 = 0x00; 87762306a36Sopenharmony_ci par->PanelVertCenterReg4 = 0x00; 87862306a36Sopenharmony_ci par->PanelVertCenterReg5 = 0x00; 87962306a36Sopenharmony_ci par->PanelHorizCenterReg1 = 0x00; 88062306a36Sopenharmony_ci par->PanelHorizCenterReg2 = 0x00; 88162306a36Sopenharmony_ci par->PanelHorizCenterReg3 = 0x00; 88262306a36Sopenharmony_ci par->PanelHorizCenterReg4 = 0x00; 88362306a36Sopenharmony_ci par->PanelHorizCenterReg5 = 0x00; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (par->PanelDispCntlReg1 & 0x02) { 88762306a36Sopenharmony_ci if (info->var.xres == par->NeoPanelWidth) { 88862306a36Sopenharmony_ci /* 88962306a36Sopenharmony_ci * No centering required when the requested display width 89062306a36Sopenharmony_ci * equals the panel width. 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_ci } else { 89362306a36Sopenharmony_ci par->PanelDispCntlReg2 |= 0x01; 89462306a36Sopenharmony_ci par->PanelDispCntlReg3 |= 0x10; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* Calculate the horizontal and vertical offsets. */ 89762306a36Sopenharmony_ci if (!lcd_stretch) { 89862306a36Sopenharmony_ci hoffset = 89962306a36Sopenharmony_ci ((par->NeoPanelWidth - 90062306a36Sopenharmony_ci info->var.xres) >> 4) - 1; 90162306a36Sopenharmony_ci voffset = 90262306a36Sopenharmony_ci ((par->NeoPanelHeight - 90362306a36Sopenharmony_ci info->var.yres) >> 1) - 2; 90462306a36Sopenharmony_ci } else { 90562306a36Sopenharmony_ci /* Stretched modes cannot be centered. */ 90662306a36Sopenharmony_ci hoffset = 0; 90762306a36Sopenharmony_ci voffset = 0; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci switch (info->var.xres) { 91162306a36Sopenharmony_ci case 320: /* Needs testing. KEM -- 24 May 98 */ 91262306a36Sopenharmony_ci par->PanelHorizCenterReg3 = hoffset; 91362306a36Sopenharmony_ci par->PanelVertCenterReg2 = voffset; 91462306a36Sopenharmony_ci break; 91562306a36Sopenharmony_ci case 400: /* Needs testing. KEM -- 24 May 98 */ 91662306a36Sopenharmony_ci par->PanelHorizCenterReg4 = hoffset; 91762306a36Sopenharmony_ci par->PanelVertCenterReg1 = voffset; 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci case 640: 92062306a36Sopenharmony_ci par->PanelHorizCenterReg1 = hoffset; 92162306a36Sopenharmony_ci par->PanelVertCenterReg3 = voffset; 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci case 800: 92462306a36Sopenharmony_ci par->PanelHorizCenterReg2 = hoffset; 92562306a36Sopenharmony_ci par->PanelVertCenterReg4 = voffset; 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci case 1024: 92862306a36Sopenharmony_ci par->PanelHorizCenterReg5 = hoffset; 92962306a36Sopenharmony_ci par->PanelVertCenterReg5 = voffset; 93062306a36Sopenharmony_ci break; 93162306a36Sopenharmony_ci case 1280: 93262306a36Sopenharmony_ci default: 93362306a36Sopenharmony_ci /* No centering in these modes. */ 93462306a36Sopenharmony_ci break; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci par->biosMode = 94062306a36Sopenharmony_ci neoFindMode(info->var.xres, info->var.yres, 94162306a36Sopenharmony_ci info->var.bits_per_pixel); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* 94462306a36Sopenharmony_ci * Calculate the VCLK that most closely matches the requested dot 94562306a36Sopenharmony_ci * clock. 94662306a36Sopenharmony_ci */ 94762306a36Sopenharmony_ci neoCalcVCLK(info, par, PICOS2KHZ(info->var.pixclock)); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* Since we program the clocks ourselves, always use VCLK3. */ 95062306a36Sopenharmony_ci par->MiscOutReg |= 0x0C; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* alread unlocked above */ 95362306a36Sopenharmony_ci /* BOGUS vga_wgfx(NULL, 0x09, 0x26); */ 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* don't know what this is, but it's 0 from bootup anyway */ 95662306a36Sopenharmony_ci vga_wgfx(NULL, 0x15, 0x00); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* was set to 0x01 by my bios in text and vesa modes */ 95962306a36Sopenharmony_ci vga_wgfx(NULL, 0x0A, par->GeneralLockReg); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci /* 96262306a36Sopenharmony_ci * The color mode needs to be set before calling vgaHWRestore 96362306a36Sopenharmony_ci * to ensure the DAC is initialized properly. 96462306a36Sopenharmony_ci * 96562306a36Sopenharmony_ci * NOTE: Make sure we don't change bits make sure we don't change 96662306a36Sopenharmony_ci * any reserved bits. 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_ci temp = vga_rgfx(NULL, 0x90); 96962306a36Sopenharmony_ci switch (info->fix.accel) { 97062306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2070: 97162306a36Sopenharmony_ci temp &= 0xF0; /* Save bits 7:4 */ 97262306a36Sopenharmony_ci temp |= (par->ExtColorModeSelect & ~0xF0); 97362306a36Sopenharmony_ci break; 97462306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2090: 97562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2093: 97662306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2097: 97762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2160: 97862306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 97962306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 98062306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 98162306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 98262306a36Sopenharmony_ci temp &= 0x70; /* Save bits 6:4 */ 98362306a36Sopenharmony_ci temp |= (par->ExtColorModeSelect & ~0x70); 98462306a36Sopenharmony_ci break; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci vga_wgfx(NULL, 0x90, temp); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci /* 99062306a36Sopenharmony_ci * In some rare cases a lockup might occur if we don't delay 99162306a36Sopenharmony_ci * here. (Reported by Miles Lane) 99262306a36Sopenharmony_ci */ 99362306a36Sopenharmony_ci //mdelay(200); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* 99662306a36Sopenharmony_ci * Disable horizontal and vertical graphics and text expansions so 99762306a36Sopenharmony_ci * that vgaHWRestore works properly. 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_ci temp = vga_rgfx(NULL, 0x25); 100062306a36Sopenharmony_ci temp &= 0x39; 100162306a36Sopenharmony_ci vga_wgfx(NULL, 0x25, temp); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* 100462306a36Sopenharmony_ci * Sleep for 200ms to make sure that the two operations above have 100562306a36Sopenharmony_ci * had time to take effect. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci mdelay(200); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* 101062306a36Sopenharmony_ci * This function handles restoring the generic VGA registers. */ 101162306a36Sopenharmony_ci vgaHWRestore(info, par); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci /* linear colormap for non palettized modes */ 101462306a36Sopenharmony_ci switch (info->var.bits_per_pixel) { 101562306a36Sopenharmony_ci case 8: 101662306a36Sopenharmony_ci /* PseudoColor, 256 */ 101762306a36Sopenharmony_ci info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 101862306a36Sopenharmony_ci break; 101962306a36Sopenharmony_ci case 16: 102062306a36Sopenharmony_ci /* TrueColor, 64k */ 102162306a36Sopenharmony_ci info->fix.visual = FB_VISUAL_TRUECOLOR; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci for (i = 0; i < 64; i++) { 102462306a36Sopenharmony_ci outb(i, 0x3c8); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci outb(i << 1, 0x3c9); 102762306a36Sopenharmony_ci outb(i, 0x3c9); 102862306a36Sopenharmony_ci outb(i << 1, 0x3c9); 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci break; 103162306a36Sopenharmony_ci case 24: 103262306a36Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET 103362306a36Sopenharmony_ci case 32: 103462306a36Sopenharmony_ci#endif 103562306a36Sopenharmony_ci /* TrueColor, 16m */ 103662306a36Sopenharmony_ci info->fix.visual = FB_VISUAL_TRUECOLOR; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci for (i = 0; i < 256; i++) { 103962306a36Sopenharmony_ci outb(i, 0x3c8); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci outb(i, 0x3c9); 104262306a36Sopenharmony_ci outb(i, 0x3c9); 104362306a36Sopenharmony_ci outb(i, 0x3c9); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci vga_wgfx(NULL, 0x0E, par->ExtCRTDispAddr); 104962306a36Sopenharmony_ci vga_wgfx(NULL, 0x0F, par->ExtCRTOffset); 105062306a36Sopenharmony_ci temp = vga_rgfx(NULL, 0x10); 105162306a36Sopenharmony_ci temp &= 0x0F; /* Save bits 3:0 */ 105262306a36Sopenharmony_ci temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */ 105362306a36Sopenharmony_ci vga_wgfx(NULL, 0x10, temp); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci vga_wgfx(NULL, 0x11, par->SysIfaceCntl2); 105662306a36Sopenharmony_ci vga_wgfx(NULL, 0x15, 0 /*par->SingleAddrPage */ ); 105762306a36Sopenharmony_ci vga_wgfx(NULL, 0x16, 0 /*par->DualAddrPage */ ); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci temp = vga_rgfx(NULL, 0x20); 106062306a36Sopenharmony_ci switch (info->fix.accel) { 106162306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2070: 106262306a36Sopenharmony_ci temp &= 0xFC; /* Save bits 7:2 */ 106362306a36Sopenharmony_ci temp |= (par->PanelDispCntlReg1 & ~0xFC); 106462306a36Sopenharmony_ci break; 106562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2090: 106662306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2093: 106762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2097: 106862306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2160: 106962306a36Sopenharmony_ci temp &= 0xDC; /* Save bits 7:6,4:2 */ 107062306a36Sopenharmony_ci temp |= (par->PanelDispCntlReg1 & ~0xDC); 107162306a36Sopenharmony_ci break; 107262306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 107362306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 107462306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 107562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 107662306a36Sopenharmony_ci temp &= 0x98; /* Save bits 7,4:3 */ 107762306a36Sopenharmony_ci temp |= (par->PanelDispCntlReg1 & ~0x98); 107862306a36Sopenharmony_ci break; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci vga_wgfx(NULL, 0x20, temp); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci temp = vga_rgfx(NULL, 0x25); 108362306a36Sopenharmony_ci temp &= 0x38; /* Save bits 5:3 */ 108462306a36Sopenharmony_ci temp |= (par->PanelDispCntlReg2 & ~0x38); 108562306a36Sopenharmony_ci vga_wgfx(NULL, 0x25, temp); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) { 108862306a36Sopenharmony_ci temp = vga_rgfx(NULL, 0x30); 108962306a36Sopenharmony_ci temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */ 109062306a36Sopenharmony_ci temp |= (par->PanelDispCntlReg3 & ~0xEF); 109162306a36Sopenharmony_ci vga_wgfx(NULL, 0x30, temp); 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci vga_wgfx(NULL, 0x28, par->PanelVertCenterReg1); 109562306a36Sopenharmony_ci vga_wgfx(NULL, 0x29, par->PanelVertCenterReg2); 109662306a36Sopenharmony_ci vga_wgfx(NULL, 0x2a, par->PanelVertCenterReg3); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) { 109962306a36Sopenharmony_ci vga_wgfx(NULL, 0x32, par->PanelVertCenterReg4); 110062306a36Sopenharmony_ci vga_wgfx(NULL, 0x33, par->PanelHorizCenterReg1); 110162306a36Sopenharmony_ci vga_wgfx(NULL, 0x34, par->PanelHorizCenterReg2); 110262306a36Sopenharmony_ci vga_wgfx(NULL, 0x35, par->PanelHorizCenterReg3); 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160) 110662306a36Sopenharmony_ci vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 || 110962306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 || 111062306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 || 111162306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) { 111262306a36Sopenharmony_ci vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4); 111362306a36Sopenharmony_ci vga_wgfx(NULL, 0x37, par->PanelVertCenterReg5); 111462306a36Sopenharmony_ci vga_wgfx(NULL, 0x38, par->PanelHorizCenterReg5); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci clock_hi = 1; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci /* Program VCLK3 if needed. */ 112062306a36Sopenharmony_ci if (par->ProgramVCLK && ((vga_rgfx(NULL, 0x9B) != par->VCLK3NumeratorLow) 112162306a36Sopenharmony_ci || (vga_rgfx(NULL, 0x9F) != par->VCLK3Denominator) 112262306a36Sopenharmony_ci || (clock_hi && ((vga_rgfx(NULL, 0x8F) & ~0x0f) 112362306a36Sopenharmony_ci != (par->VCLK3NumeratorHigh & 112462306a36Sopenharmony_ci ~0x0F))))) { 112562306a36Sopenharmony_ci vga_wgfx(NULL, 0x9B, par->VCLK3NumeratorLow); 112662306a36Sopenharmony_ci if (clock_hi) { 112762306a36Sopenharmony_ci temp = vga_rgfx(NULL, 0x8F); 112862306a36Sopenharmony_ci temp &= 0x0F; /* Save bits 3:0 */ 112962306a36Sopenharmony_ci temp |= (par->VCLK3NumeratorHigh & ~0x0F); 113062306a36Sopenharmony_ci vga_wgfx(NULL, 0x8F, temp); 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci vga_wgfx(NULL, 0x9F, par->VCLK3Denominator); 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (par->biosMode) 113662306a36Sopenharmony_ci vga_wcrt(NULL, 0x23, par->biosMode); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci vga_wgfx(NULL, 0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */ 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci /* Program vertical extension register */ 114162306a36Sopenharmony_ci if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 || 114262306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 || 114362306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 || 114462306a36Sopenharmony_ci info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) { 114562306a36Sopenharmony_ci vga_wcrt(NULL, 0x70, par->VerticalExt); 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci vgaHWProtect(0); /* Turn on screen */ 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* Calling this also locks offset registers required in update_start */ 115162306a36Sopenharmony_ci neoLock(&par->state); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci info->fix.line_length = 115462306a36Sopenharmony_ci info->var.xres_virtual * (info->var.bits_per_pixel >> 3); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci switch (info->fix.accel) { 115762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 115862306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 115962306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 116062306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 116162306a36Sopenharmony_ci neo2200_accel_init(info, &info->var); 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci default: 116462306a36Sopenharmony_ci break; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci return 0; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci/* 117062306a36Sopenharmony_ci * Pan or Wrap the Display 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_cistatic int neofb_pan_display(struct fb_var_screeninfo *var, 117362306a36Sopenharmony_ci struct fb_info *info) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci struct neofb_par *par = info->par; 117662306a36Sopenharmony_ci struct vgastate *state = &par->state; 117762306a36Sopenharmony_ci int oldExtCRTDispAddr; 117862306a36Sopenharmony_ci int Base; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci DBG("neofb_update_start"); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci Base = (var->yoffset * info->var.xres_virtual + var->xoffset) >> 2; 118362306a36Sopenharmony_ci Base *= (info->var.bits_per_pixel + 7) / 8; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci neoUnlock(); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci /* 118862306a36Sopenharmony_ci * These are the generic starting address registers. 118962306a36Sopenharmony_ci */ 119062306a36Sopenharmony_ci vga_wcrt(state->vgabase, 0x0C, (Base & 0x00FF00) >> 8); 119162306a36Sopenharmony_ci vga_wcrt(state->vgabase, 0x0D, (Base & 0x00FF)); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* 119462306a36Sopenharmony_ci * Make sure we don't clobber some other bits that might already 119562306a36Sopenharmony_ci * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't 119662306a36Sopenharmony_ci * be needed. 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci oldExtCRTDispAddr = vga_rgfx(NULL, 0x0E); 119962306a36Sopenharmony_ci vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0))); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci neoLock(state); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci return 0; 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 120762306a36Sopenharmony_ci u_int transp, struct fb_info *fb) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci if (regno >= fb->cmap.len || regno > 255) 121062306a36Sopenharmony_ci return -EINVAL; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if (fb->var.bits_per_pixel <= 8) { 121362306a36Sopenharmony_ci outb(regno, 0x3c8); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci outb(red >> 10, 0x3c9); 121662306a36Sopenharmony_ci outb(green >> 10, 0x3c9); 121762306a36Sopenharmony_ci outb(blue >> 10, 0x3c9); 121862306a36Sopenharmony_ci } else if (regno < 16) { 121962306a36Sopenharmony_ci switch (fb->var.bits_per_pixel) { 122062306a36Sopenharmony_ci case 16: 122162306a36Sopenharmony_ci ((u32 *) fb->pseudo_palette)[regno] = 122262306a36Sopenharmony_ci ((red & 0xf800)) | ((green & 0xfc00) >> 5) | 122362306a36Sopenharmony_ci ((blue & 0xf800) >> 11); 122462306a36Sopenharmony_ci break; 122562306a36Sopenharmony_ci case 24: 122662306a36Sopenharmony_ci ((u32 *) fb->pseudo_palette)[regno] = 122762306a36Sopenharmony_ci ((red & 0xff00) << 8) | ((green & 0xff00)) | 122862306a36Sopenharmony_ci ((blue & 0xff00) >> 8); 122962306a36Sopenharmony_ci break; 123062306a36Sopenharmony_ci#ifdef NO_32BIT_SUPPORT_YET 123162306a36Sopenharmony_ci case 32: 123262306a36Sopenharmony_ci ((u32 *) fb->pseudo_palette)[regno] = 123362306a36Sopenharmony_ci ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) | 123462306a36Sopenharmony_ci ((green & 0xff00)) | ((blue & 0xff00) >> 8); 123562306a36Sopenharmony_ci break; 123662306a36Sopenharmony_ci#endif 123762306a36Sopenharmony_ci default: 123862306a36Sopenharmony_ci return 1; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci return 0; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci/* 124662306a36Sopenharmony_ci * (Un)Blank the display. 124762306a36Sopenharmony_ci */ 124862306a36Sopenharmony_cistatic int neofb_blank(int blank_mode, struct fb_info *info) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci /* 125162306a36Sopenharmony_ci * Blank the screen if blank_mode != 0, else unblank. 125262306a36Sopenharmony_ci * Return 0 if blanking succeeded, != 0 if un-/blanking failed due to 125362306a36Sopenharmony_ci * e.g. a video mode which doesn't support it. Implements VESA suspend 125462306a36Sopenharmony_ci * and powerdown modes for monitors, and backlight control on LCDs. 125562306a36Sopenharmony_ci * blank_mode == 0: unblanked (backlight on) 125662306a36Sopenharmony_ci * blank_mode == 1: blank (backlight on) 125762306a36Sopenharmony_ci * blank_mode == 2: suspend vsync (backlight off) 125862306a36Sopenharmony_ci * blank_mode == 3: suspend hsync (backlight off) 125962306a36Sopenharmony_ci * blank_mode == 4: powerdown (backlight off) 126062306a36Sopenharmony_ci * 126162306a36Sopenharmony_ci * wms...Enable VESA DPMS compatible powerdown mode 126262306a36Sopenharmony_ci * run "setterm -powersave powerdown" to take advantage 126362306a36Sopenharmony_ci */ 126462306a36Sopenharmony_ci struct neofb_par *par = info->par; 126562306a36Sopenharmony_ci int seqflags, lcdflags, dpmsflags, reg, tmpdisp; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* 126862306a36Sopenharmony_ci * Read back the register bits related to display configuration. They might 126962306a36Sopenharmony_ci * have been changed underneath the driver via Fn key stroke. 127062306a36Sopenharmony_ci */ 127162306a36Sopenharmony_ci neoUnlock(); 127262306a36Sopenharmony_ci tmpdisp = vga_rgfx(NULL, 0x20) & 0x03; 127362306a36Sopenharmony_ci neoLock(&par->state); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* In case we blank the screen, we want to store the possibly new 127662306a36Sopenharmony_ci * configuration in the driver. During un-blank, we re-apply this setting, 127762306a36Sopenharmony_ci * since the LCD bit will be cleared in order to switch off the backlight. 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_ci if (par->PanelDispCntlRegRead) { 128062306a36Sopenharmony_ci par->PanelDispCntlReg1 = tmpdisp; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci par->PanelDispCntlRegRead = !blank_mode; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci switch (blank_mode) { 128562306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: /* powerdown - both sync lines down */ 128662306a36Sopenharmony_ci seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ 128762306a36Sopenharmony_ci lcdflags = 0; /* LCD off */ 128862306a36Sopenharmony_ci dpmsflags = NEO_GR01_SUPPRESS_HSYNC | 128962306a36Sopenharmony_ci NEO_GR01_SUPPRESS_VSYNC; 129062306a36Sopenharmony_ci#ifdef CONFIG_TOSHIBA 129162306a36Sopenharmony_ci /* Do we still need this ? */ 129262306a36Sopenharmony_ci /* attempt to turn off backlight on toshiba; also turns off external */ 129362306a36Sopenharmony_ci { 129462306a36Sopenharmony_ci SMMRegisters regs; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci regs.eax = 0xff00; /* HCI_SET */ 129762306a36Sopenharmony_ci regs.ebx = 0x0002; /* HCI_BACKLIGHT */ 129862306a36Sopenharmony_ci regs.ecx = 0x0000; /* HCI_DISABLE */ 129962306a36Sopenharmony_ci tosh_smm(®s); 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci#endif 130262306a36Sopenharmony_ci break; 130362306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: /* hsync off */ 130462306a36Sopenharmony_ci seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ 130562306a36Sopenharmony_ci lcdflags = 0; /* LCD off */ 130662306a36Sopenharmony_ci dpmsflags = NEO_GR01_SUPPRESS_HSYNC; 130762306a36Sopenharmony_ci break; 130862306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: /* vsync off */ 130962306a36Sopenharmony_ci seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ 131062306a36Sopenharmony_ci lcdflags = 0; /* LCD off */ 131162306a36Sopenharmony_ci dpmsflags = NEO_GR01_SUPPRESS_VSYNC; 131262306a36Sopenharmony_ci break; 131362306a36Sopenharmony_ci case FB_BLANK_NORMAL: /* just blank screen (backlight stays on) */ 131462306a36Sopenharmony_ci seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */ 131562306a36Sopenharmony_ci /* 131662306a36Sopenharmony_ci * During a blank operation with the LID shut, we might store "LCD off" 131762306a36Sopenharmony_ci * by mistake. Due to timing issues, the BIOS may switch the lights 131862306a36Sopenharmony_ci * back on, and we turn it back off once we "unblank". 131962306a36Sopenharmony_ci * 132062306a36Sopenharmony_ci * So here is an attempt to implement ">=" - if we are in the process 132162306a36Sopenharmony_ci * of unblanking, and the LCD bit is unset in the driver but set in the 132262306a36Sopenharmony_ci * register, we must keep it. 132362306a36Sopenharmony_ci */ 132462306a36Sopenharmony_ci lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */ 132562306a36Sopenharmony_ci dpmsflags = 0x00; /* no hsync/vsync suppression */ 132662306a36Sopenharmony_ci break; 132762306a36Sopenharmony_ci case FB_BLANK_UNBLANK: /* unblank */ 132862306a36Sopenharmony_ci seqflags = 0; /* Enable sequencer */ 132962306a36Sopenharmony_ci lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */ 133062306a36Sopenharmony_ci dpmsflags = 0x00; /* no hsync/vsync suppression */ 133162306a36Sopenharmony_ci#ifdef CONFIG_TOSHIBA 133262306a36Sopenharmony_ci /* Do we still need this ? */ 133362306a36Sopenharmony_ci /* attempt to re-enable backlight/external on toshiba */ 133462306a36Sopenharmony_ci { 133562306a36Sopenharmony_ci SMMRegisters regs; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci regs.eax = 0xff00; /* HCI_SET */ 133862306a36Sopenharmony_ci regs.ebx = 0x0002; /* HCI_BACKLIGHT */ 133962306a36Sopenharmony_ci regs.ecx = 0x0001; /* HCI_ENABLE */ 134062306a36Sopenharmony_ci tosh_smm(®s); 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci#endif 134362306a36Sopenharmony_ci break; 134462306a36Sopenharmony_ci default: /* Anything else we don't understand; return 1 to tell 134562306a36Sopenharmony_ci * fb_blank we didn't aactually do anything */ 134662306a36Sopenharmony_ci return 1; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci neoUnlock(); 135062306a36Sopenharmony_ci reg = (vga_rseq(NULL, 0x01) & ~0x20) | seqflags; 135162306a36Sopenharmony_ci vga_wseq(NULL, 0x01, reg); 135262306a36Sopenharmony_ci reg = (vga_rgfx(NULL, 0x20) & ~0x02) | lcdflags; 135362306a36Sopenharmony_ci vga_wgfx(NULL, 0x20, reg); 135462306a36Sopenharmony_ci reg = (vga_rgfx(NULL, 0x01) & ~0xF0) | 0x80 | dpmsflags; 135562306a36Sopenharmony_ci vga_wgfx(NULL, 0x01, reg); 135662306a36Sopenharmony_ci neoLock(&par->state); 135762306a36Sopenharmony_ci return 0; 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_cistatic void 136162306a36Sopenharmony_cineo2200_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci struct neofb_par *par = info->par; 136462306a36Sopenharmony_ci u_long dst, rop; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci dst = rect->dx + rect->dy * info->var.xres_virtual; 136762306a36Sopenharmony_ci rop = rect->rop ? 0x060000 : 0x0c0000; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci neo2200_wait_fifo(info, 4); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci /* set blt control */ 137262306a36Sopenharmony_ci writel(NEO_BC3_FIFO_EN | 137362306a36Sopenharmony_ci NEO_BC0_SRC_IS_FG | NEO_BC3_SKIP_MAPPING | 137462306a36Sopenharmony_ci // NEO_BC3_DST_XY_ADDR | 137562306a36Sopenharmony_ci // NEO_BC3_SRC_XY_ADDR | 137662306a36Sopenharmony_ci rop, &par->neo2200->bltCntl); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci switch (info->var.bits_per_pixel) { 137962306a36Sopenharmony_ci case 8: 138062306a36Sopenharmony_ci writel(rect->color, &par->neo2200->fgColor); 138162306a36Sopenharmony_ci break; 138262306a36Sopenharmony_ci case 16: 138362306a36Sopenharmony_ci case 24: 138462306a36Sopenharmony_ci writel(((u32 *) (info->pseudo_palette))[rect->color], 138562306a36Sopenharmony_ci &par->neo2200->fgColor); 138662306a36Sopenharmony_ci break; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci writel(dst * ((info->var.bits_per_pixel + 7) >> 3), 139062306a36Sopenharmony_ci &par->neo2200->dstStart); 139162306a36Sopenharmony_ci writel((rect->height << 16) | (rect->width & 0xffff), 139262306a36Sopenharmony_ci &par->neo2200->xyExt); 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_cistatic void 139662306a36Sopenharmony_cineo2200_copyarea(struct fb_info *info, const struct fb_copyarea *area) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy; 139962306a36Sopenharmony_ci struct neofb_par *par = info->par; 140062306a36Sopenharmony_ci u_long src, dst, bltCntl; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci bltCntl = NEO_BC3_FIFO_EN | NEO_BC3_SKIP_MAPPING | 0x0C0000; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if ((dy > sy) || ((dy == sy) && (dx > sx))) { 140562306a36Sopenharmony_ci /* Start with the lower right corner */ 140662306a36Sopenharmony_ci sy += (area->height - 1); 140762306a36Sopenharmony_ci dy += (area->height - 1); 140862306a36Sopenharmony_ci sx += (area->width - 1); 140962306a36Sopenharmony_ci dx += (area->width - 1); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci bltCntl |= NEO_BC0_X_DEC | NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci src = sx * (info->var.bits_per_pixel >> 3) + sy*info->fix.line_length; 141562306a36Sopenharmony_ci dst = dx * (info->var.bits_per_pixel >> 3) + dy*info->fix.line_length; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci neo2200_wait_fifo(info, 4); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* set blt control */ 142062306a36Sopenharmony_ci writel(bltCntl, &par->neo2200->bltCntl); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci writel(src, &par->neo2200->srcStart); 142362306a36Sopenharmony_ci writel(dst, &par->neo2200->dstStart); 142462306a36Sopenharmony_ci writel((area->height << 16) | (area->width & 0xffff), 142562306a36Sopenharmony_ci &par->neo2200->xyExt); 142662306a36Sopenharmony_ci} 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_cistatic void 142962306a36Sopenharmony_cineo2200_imageblit(struct fb_info *info, const struct fb_image *image) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci struct neofb_par *par = info->par; 143262306a36Sopenharmony_ci int s_pitch = (image->width * image->depth + 7) >> 3; 143362306a36Sopenharmony_ci int scan_align = info->pixmap.scan_align - 1; 143462306a36Sopenharmony_ci int buf_align = info->pixmap.buf_align - 1; 143562306a36Sopenharmony_ci int bltCntl_flags, d_pitch, data_len; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci // The data is padded for the hardware 143862306a36Sopenharmony_ci d_pitch = (s_pitch + scan_align) & ~scan_align; 143962306a36Sopenharmony_ci data_len = ((d_pitch * image->height) + buf_align) & ~buf_align; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci neo2200_sync(info); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (image->depth == 1) { 144462306a36Sopenharmony_ci if (info->var.bits_per_pixel == 24 && image->width < 16) { 144562306a36Sopenharmony_ci /* FIXME. There is a bug with accelerated color-expanded 144662306a36Sopenharmony_ci * transfers in 24 bit mode if the image being transferred 144762306a36Sopenharmony_ci * is less than 16 bits wide. This is due to insufficient 144862306a36Sopenharmony_ci * padding when writing the image. We need to adjust 144962306a36Sopenharmony_ci * struct fb_pixmap. Not yet done. */ 145062306a36Sopenharmony_ci cfb_imageblit(info, image); 145162306a36Sopenharmony_ci return; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci bltCntl_flags = NEO_BC0_SRC_MONO; 145462306a36Sopenharmony_ci } else if (image->depth == info->var.bits_per_pixel) { 145562306a36Sopenharmony_ci bltCntl_flags = 0; 145662306a36Sopenharmony_ci } else { 145762306a36Sopenharmony_ci /* We don't currently support hardware acceleration if image 145862306a36Sopenharmony_ci * depth is different from display */ 145962306a36Sopenharmony_ci cfb_imageblit(info, image); 146062306a36Sopenharmony_ci return; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci switch (info->var.bits_per_pixel) { 146462306a36Sopenharmony_ci case 8: 146562306a36Sopenharmony_ci writel(image->fg_color, &par->neo2200->fgColor); 146662306a36Sopenharmony_ci writel(image->bg_color, &par->neo2200->bgColor); 146762306a36Sopenharmony_ci break; 146862306a36Sopenharmony_ci case 16: 146962306a36Sopenharmony_ci case 24: 147062306a36Sopenharmony_ci writel(((u32 *) (info->pseudo_palette))[image->fg_color], 147162306a36Sopenharmony_ci &par->neo2200->fgColor); 147262306a36Sopenharmony_ci writel(((u32 *) (info->pseudo_palette))[image->bg_color], 147362306a36Sopenharmony_ci &par->neo2200->bgColor); 147462306a36Sopenharmony_ci break; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci writel(NEO_BC0_SYS_TO_VID | 147862306a36Sopenharmony_ci NEO_BC3_SKIP_MAPPING | bltCntl_flags | 147962306a36Sopenharmony_ci // NEO_BC3_DST_XY_ADDR | 148062306a36Sopenharmony_ci 0x0c0000, &par->neo2200->bltCntl); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci writel(0, &par->neo2200->srcStart); 148362306a36Sopenharmony_ci// par->neo2200->dstStart = (image->dy << 16) | (image->dx & 0xffff); 148462306a36Sopenharmony_ci writel(((image->dx & 0xffff) * (info->var.bits_per_pixel >> 3) + 148562306a36Sopenharmony_ci image->dy * info->fix.line_length), &par->neo2200->dstStart); 148662306a36Sopenharmony_ci writel((image->height << 16) | (image->width & 0xffff), 148762306a36Sopenharmony_ci &par->neo2200->xyExt); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci memcpy_toio(par->mmio_vbase + 0x100000, image->data, data_len); 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic void 149362306a36Sopenharmony_cineofb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci switch (info->fix.accel) { 149662306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 149762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 149862306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 149962306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 150062306a36Sopenharmony_ci neo2200_fillrect(info, rect); 150162306a36Sopenharmony_ci break; 150262306a36Sopenharmony_ci default: 150362306a36Sopenharmony_ci cfb_fillrect(info, rect); 150462306a36Sopenharmony_ci break; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistatic void 150962306a36Sopenharmony_cineofb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci switch (info->fix.accel) { 151262306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 151362306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 151462306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 151562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 151662306a36Sopenharmony_ci neo2200_copyarea(info, area); 151762306a36Sopenharmony_ci break; 151862306a36Sopenharmony_ci default: 151962306a36Sopenharmony_ci cfb_copyarea(info, area); 152062306a36Sopenharmony_ci break; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cistatic void 152562306a36Sopenharmony_cineofb_imageblit(struct fb_info *info, const struct fb_image *image) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci switch (info->fix.accel) { 152862306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 152962306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 153062306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 153162306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 153262306a36Sopenharmony_ci neo2200_imageblit(info, image); 153362306a36Sopenharmony_ci break; 153462306a36Sopenharmony_ci default: 153562306a36Sopenharmony_ci cfb_imageblit(info, image); 153662306a36Sopenharmony_ci break; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci} 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cistatic int 154162306a36Sopenharmony_cineofb_sync(struct fb_info *info) 154262306a36Sopenharmony_ci{ 154362306a36Sopenharmony_ci switch (info->fix.accel) { 154462306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 154562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 154662306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 154762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 154862306a36Sopenharmony_ci neo2200_sync(info); 154962306a36Sopenharmony_ci break; 155062306a36Sopenharmony_ci default: 155162306a36Sopenharmony_ci break; 155262306a36Sopenharmony_ci } 155362306a36Sopenharmony_ci return 0; 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci/* 155762306a36Sopenharmony_cistatic void 155862306a36Sopenharmony_cineofb_draw_cursor(struct fb_info *info, u8 *dst, u8 *src, unsigned int width) 155962306a36Sopenharmony_ci{ 156062306a36Sopenharmony_ci //memset_io(info->sprite.addr, 0xff, 1); 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic int 156462306a36Sopenharmony_cineofb_cursor(struct fb_info *info, struct fb_cursor *cursor) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci struct neofb_par *par = (struct neofb_par *) info->par; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci * Disable cursor * 156962306a36Sopenharmony_ci write_le32(NEOREG_CURSCNTL, ~NEO_CURS_ENABLE, par); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETPOS) { 157262306a36Sopenharmony_ci u32 x = cursor->image.dx; 157362306a36Sopenharmony_ci u32 y = cursor->image.dy; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci info->cursor.image.dx = x; 157662306a36Sopenharmony_ci info->cursor.image.dy = y; 157762306a36Sopenharmony_ci write_le32(NEOREG_CURSX, x, par); 157862306a36Sopenharmony_ci write_le32(NEOREG_CURSY, y, par); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETSIZE) { 158262306a36Sopenharmony_ci info->cursor.image.height = cursor->image.height; 158362306a36Sopenharmony_ci info->cursor.image.width = cursor->image.width; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETHOT) 158762306a36Sopenharmony_ci info->cursor.hot = cursor->hot; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETCMAP) { 159062306a36Sopenharmony_ci if (cursor->image.depth == 1) { 159162306a36Sopenharmony_ci u32 fg = cursor->image.fg_color; 159262306a36Sopenharmony_ci u32 bg = cursor->image.bg_color; 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci info->cursor.image.fg_color = fg; 159562306a36Sopenharmony_ci info->cursor.image.bg_color = bg; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci fg = ((fg & 0xff0000) >> 16) | ((fg & 0xff) << 16) | (fg & 0xff00); 159862306a36Sopenharmony_ci bg = ((bg & 0xff0000) >> 16) | ((bg & 0xff) << 16) | (bg & 0xff00); 159962306a36Sopenharmony_ci write_le32(NEOREG_CURSFGCOLOR, fg, par); 160062306a36Sopenharmony_ci write_le32(NEOREG_CURSBGCOLOR, bg, par); 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETSHAPE) 160562306a36Sopenharmony_ci fb_load_cursor_image(info); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (info->cursor.enable) 160862306a36Sopenharmony_ci write_le32(NEOREG_CURSCNTL, NEO_CURS_ENABLE, par); 160962306a36Sopenharmony_ci return 0; 161062306a36Sopenharmony_ci} 161162306a36Sopenharmony_ci*/ 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_cistatic const struct fb_ops neofb_ops = { 161462306a36Sopenharmony_ci .owner = THIS_MODULE, 161562306a36Sopenharmony_ci .fb_open = neofb_open, 161662306a36Sopenharmony_ci .fb_release = neofb_release, 161762306a36Sopenharmony_ci .fb_check_var = neofb_check_var, 161862306a36Sopenharmony_ci .fb_set_par = neofb_set_par, 161962306a36Sopenharmony_ci .fb_setcolreg = neofb_setcolreg, 162062306a36Sopenharmony_ci .fb_pan_display = neofb_pan_display, 162162306a36Sopenharmony_ci .fb_blank = neofb_blank, 162262306a36Sopenharmony_ci .fb_sync = neofb_sync, 162362306a36Sopenharmony_ci .fb_fillrect = neofb_fillrect, 162462306a36Sopenharmony_ci .fb_copyarea = neofb_copyarea, 162562306a36Sopenharmony_ci .fb_imageblit = neofb_imageblit, 162662306a36Sopenharmony_ci}; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_cistatic struct fb_videomode mode800x480 = { 163162306a36Sopenharmony_ci .xres = 800, 163262306a36Sopenharmony_ci .yres = 480, 163362306a36Sopenharmony_ci .pixclock = 25000, 163462306a36Sopenharmony_ci .left_margin = 88, 163562306a36Sopenharmony_ci .right_margin = 40, 163662306a36Sopenharmony_ci .upper_margin = 23, 163762306a36Sopenharmony_ci .lower_margin = 1, 163862306a36Sopenharmony_ci .hsync_len = 128, 163962306a36Sopenharmony_ci .vsync_len = 4, 164062306a36Sopenharmony_ci .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 164162306a36Sopenharmony_ci .vmode = FB_VMODE_NONINTERLACED 164262306a36Sopenharmony_ci}; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_cistatic int neo_map_mmio(struct fb_info *info, struct pci_dev *dev) 164562306a36Sopenharmony_ci{ 164662306a36Sopenharmony_ci struct neofb_par *par = info->par; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci DBG("neo_map_mmio"); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci switch (info->fix.accel) { 165162306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2070: 165262306a36Sopenharmony_ci info->fix.mmio_start = pci_resource_start(dev, 0)+ 165362306a36Sopenharmony_ci 0x100000; 165462306a36Sopenharmony_ci break; 165562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2090: 165662306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2093: 165762306a36Sopenharmony_ci info->fix.mmio_start = pci_resource_start(dev, 0)+ 165862306a36Sopenharmony_ci 0x200000; 165962306a36Sopenharmony_ci break; 166062306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2160: 166162306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2097: 166262306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 166362306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 166462306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 166562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 166662306a36Sopenharmony_ci info->fix.mmio_start = pci_resource_start(dev, 1); 166762306a36Sopenharmony_ci break; 166862306a36Sopenharmony_ci default: 166962306a36Sopenharmony_ci info->fix.mmio_start = pci_resource_start(dev, 0); 167062306a36Sopenharmony_ci } 167162306a36Sopenharmony_ci info->fix.mmio_len = MMIO_SIZE; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (!request_mem_region 167462306a36Sopenharmony_ci (info->fix.mmio_start, MMIO_SIZE, "memory mapped I/O")) { 167562306a36Sopenharmony_ci printk("neofb: memory mapped IO in use\n"); 167662306a36Sopenharmony_ci return -EBUSY; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci par->mmio_vbase = ioremap(info->fix.mmio_start, MMIO_SIZE); 168062306a36Sopenharmony_ci if (!par->mmio_vbase) { 168162306a36Sopenharmony_ci printk("neofb: unable to map memory mapped IO\n"); 168262306a36Sopenharmony_ci release_mem_region(info->fix.mmio_start, 168362306a36Sopenharmony_ci info->fix.mmio_len); 168462306a36Sopenharmony_ci return -ENOMEM; 168562306a36Sopenharmony_ci } else 168662306a36Sopenharmony_ci printk(KERN_INFO "neofb: mapped io at %p\n", 168762306a36Sopenharmony_ci par->mmio_vbase); 168862306a36Sopenharmony_ci return 0; 168962306a36Sopenharmony_ci} 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_cistatic void neo_unmap_mmio(struct fb_info *info) 169262306a36Sopenharmony_ci{ 169362306a36Sopenharmony_ci struct neofb_par *par = info->par; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci DBG("neo_unmap_mmio"); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci iounmap(par->mmio_vbase); 169862306a36Sopenharmony_ci par->mmio_vbase = NULL; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci release_mem_region(info->fix.mmio_start, 170162306a36Sopenharmony_ci info->fix.mmio_len); 170262306a36Sopenharmony_ci} 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_cistatic int neo_map_video(struct fb_info *info, struct pci_dev *dev, 170562306a36Sopenharmony_ci int video_len) 170662306a36Sopenharmony_ci{ 170762306a36Sopenharmony_ci //unsigned long addr; 170862306a36Sopenharmony_ci struct neofb_par *par = info->par; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci DBG("neo_map_video"); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci info->fix.smem_start = pci_resource_start(dev, 0); 171362306a36Sopenharmony_ci info->fix.smem_len = video_len; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, 171662306a36Sopenharmony_ci "frame buffer")) { 171762306a36Sopenharmony_ci printk("neofb: frame buffer in use\n"); 171862306a36Sopenharmony_ci return -EBUSY; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci info->screen_base = 172262306a36Sopenharmony_ci ioremap_wc(info->fix.smem_start, info->fix.smem_len); 172362306a36Sopenharmony_ci if (!info->screen_base) { 172462306a36Sopenharmony_ci printk("neofb: unable to map screen memory\n"); 172562306a36Sopenharmony_ci release_mem_region(info->fix.smem_start, 172662306a36Sopenharmony_ci info->fix.smem_len); 172762306a36Sopenharmony_ci return -ENOMEM; 172862306a36Sopenharmony_ci } else 172962306a36Sopenharmony_ci printk(KERN_INFO "neofb: mapped framebuffer at %p\n", 173062306a36Sopenharmony_ci info->screen_base); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci par->wc_cookie = arch_phys_wc_add(info->fix.smem_start, 173362306a36Sopenharmony_ci pci_resource_len(dev, 0)); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci /* Clear framebuffer, it's all white in memory after boot */ 173662306a36Sopenharmony_ci memset_io(info->screen_base, 0, info->fix.smem_len); 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci /* Allocate Cursor drawing pad. 173962306a36Sopenharmony_ci info->fix.smem_len -= PAGE_SIZE; 174062306a36Sopenharmony_ci addr = info->fix.smem_start + info->fix.smem_len; 174162306a36Sopenharmony_ci write_le32(NEOREG_CURSMEMPOS, ((0x000f & (addr >> 10)) << 8) | 174262306a36Sopenharmony_ci ((0x0ff0 & (addr >> 10)) >> 4), par); 174362306a36Sopenharmony_ci addr = (unsigned long) info->screen_base + info->fix.smem_len; 174462306a36Sopenharmony_ci info->sprite.addr = (u8 *) addr; */ 174562306a36Sopenharmony_ci return 0; 174662306a36Sopenharmony_ci} 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_cistatic void neo_unmap_video(struct fb_info *info) 174962306a36Sopenharmony_ci{ 175062306a36Sopenharmony_ci struct neofb_par *par = info->par; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci DBG("neo_unmap_video"); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci arch_phys_wc_del(par->wc_cookie); 175562306a36Sopenharmony_ci iounmap(info->screen_base); 175662306a36Sopenharmony_ci info->screen_base = NULL; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci release_mem_region(info->fix.smem_start, 175962306a36Sopenharmony_ci info->fix.smem_len); 176062306a36Sopenharmony_ci} 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_cistatic int neo_scan_monitor(struct fb_info *info) 176362306a36Sopenharmony_ci{ 176462306a36Sopenharmony_ci struct neofb_par *par = info->par; 176562306a36Sopenharmony_ci unsigned char type, display; 176662306a36Sopenharmony_ci int w; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci // Eventually we will have i2c support. 176962306a36Sopenharmony_ci info->monspecs.modedb = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL); 177062306a36Sopenharmony_ci if (!info->monspecs.modedb) 177162306a36Sopenharmony_ci return -ENOMEM; 177262306a36Sopenharmony_ci info->monspecs.modedb_len = 1; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* Determine the panel type */ 177562306a36Sopenharmony_ci vga_wgfx(NULL, 0x09, 0x26); 177662306a36Sopenharmony_ci type = vga_rgfx(NULL, 0x21); 177762306a36Sopenharmony_ci display = vga_rgfx(NULL, 0x20); 177862306a36Sopenharmony_ci if (!par->internal_display && !par->external_display) { 177962306a36Sopenharmony_ci par->internal_display = display & 2 || !(display & 3) ? 1 : 0; 178062306a36Sopenharmony_ci par->external_display = display & 1; 178162306a36Sopenharmony_ci printk (KERN_INFO "Autodetected %s display\n", 178262306a36Sopenharmony_ci par->internal_display && par->external_display ? "simultaneous" : 178362306a36Sopenharmony_ci par->internal_display ? "internal" : "external"); 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* Determine panel width -- used in NeoValidMode. */ 178762306a36Sopenharmony_ci w = vga_rgfx(NULL, 0x20); 178862306a36Sopenharmony_ci vga_wgfx(NULL, 0x09, 0x00); 178962306a36Sopenharmony_ci switch ((w & 0x18) >> 3) { 179062306a36Sopenharmony_ci case 0x00: 179162306a36Sopenharmony_ci // 640x480@60 179262306a36Sopenharmony_ci par->NeoPanelWidth = 640; 179362306a36Sopenharmony_ci par->NeoPanelHeight = 480; 179462306a36Sopenharmony_ci memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode)); 179562306a36Sopenharmony_ci break; 179662306a36Sopenharmony_ci case 0x01: 179762306a36Sopenharmony_ci par->NeoPanelWidth = 800; 179862306a36Sopenharmony_ci if (par->libretto) { 179962306a36Sopenharmony_ci par->NeoPanelHeight = 480; 180062306a36Sopenharmony_ci memcpy(info->monspecs.modedb, &mode800x480, sizeof(struct fb_videomode)); 180162306a36Sopenharmony_ci } else { 180262306a36Sopenharmony_ci // 800x600@60 180362306a36Sopenharmony_ci par->NeoPanelHeight = 600; 180462306a36Sopenharmony_ci memcpy(info->monspecs.modedb, &vesa_modes[8], sizeof(struct fb_videomode)); 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci break; 180762306a36Sopenharmony_ci case 0x02: 180862306a36Sopenharmony_ci // 1024x768@60 180962306a36Sopenharmony_ci par->NeoPanelWidth = 1024; 181062306a36Sopenharmony_ci par->NeoPanelHeight = 768; 181162306a36Sopenharmony_ci memcpy(info->monspecs.modedb, &vesa_modes[13], sizeof(struct fb_videomode)); 181262306a36Sopenharmony_ci break; 181362306a36Sopenharmony_ci case 0x03: 181462306a36Sopenharmony_ci /* 1280x1024@60 panel support needs to be added */ 181562306a36Sopenharmony_ci#ifdef NOT_DONE 181662306a36Sopenharmony_ci par->NeoPanelWidth = 1280; 181762306a36Sopenharmony_ci par->NeoPanelHeight = 1024; 181862306a36Sopenharmony_ci memcpy(info->monspecs.modedb, &vesa_modes[20], sizeof(struct fb_videomode)); 181962306a36Sopenharmony_ci break; 182062306a36Sopenharmony_ci#else 182162306a36Sopenharmony_ci printk(KERN_ERR 182262306a36Sopenharmony_ci "neofb: Only 640x480, 800x600/480 and 1024x768 panels are currently supported\n"); 182362306a36Sopenharmony_ci kfree(info->monspecs.modedb); 182462306a36Sopenharmony_ci return -1; 182562306a36Sopenharmony_ci#endif 182662306a36Sopenharmony_ci default: 182762306a36Sopenharmony_ci // 640x480@60 182862306a36Sopenharmony_ci par->NeoPanelWidth = 640; 182962306a36Sopenharmony_ci par->NeoPanelHeight = 480; 183062306a36Sopenharmony_ci memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode)); 183162306a36Sopenharmony_ci break; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci printk(KERN_INFO "Panel is a %dx%d %s %s display\n", 183562306a36Sopenharmony_ci par->NeoPanelWidth, 183662306a36Sopenharmony_ci par->NeoPanelHeight, 183762306a36Sopenharmony_ci (type & 0x02) ? "color" : "monochrome", 183862306a36Sopenharmony_ci (type & 0x10) ? "TFT" : "dual scan"); 183962306a36Sopenharmony_ci return 0; 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_cistatic int neo_init_hw(struct fb_info *info) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci struct neofb_par *par = info->par; 184562306a36Sopenharmony_ci int videoRam = 896; 184662306a36Sopenharmony_ci int maxClock = 65000; 184762306a36Sopenharmony_ci int CursorOff = 0x100; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci DBG("neo_init_hw"); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci neoUnlock(); 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci#if 0 185462306a36Sopenharmony_ci printk(KERN_DEBUG "--- Neo extended register dump ---\n"); 185562306a36Sopenharmony_ci for (int w = 0; w < 0x85; w++) 185662306a36Sopenharmony_ci printk(KERN_DEBUG "CR %p: %p\n", (void *) w, 185762306a36Sopenharmony_ci (void *) vga_rcrt(NULL, w)); 185862306a36Sopenharmony_ci for (int w = 0; w < 0xC7; w++) 185962306a36Sopenharmony_ci printk(KERN_DEBUG "GR %p: %p\n", (void *) w, 186062306a36Sopenharmony_ci (void *) vga_rgfx(NULL, w)); 186162306a36Sopenharmony_ci#endif 186262306a36Sopenharmony_ci switch (info->fix.accel) { 186362306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2070: 186462306a36Sopenharmony_ci videoRam = 896; 186562306a36Sopenharmony_ci maxClock = 65000; 186662306a36Sopenharmony_ci break; 186762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2090: 186862306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2093: 186962306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2097: 187062306a36Sopenharmony_ci videoRam = 1152; 187162306a36Sopenharmony_ci maxClock = 80000; 187262306a36Sopenharmony_ci break; 187362306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2160: 187462306a36Sopenharmony_ci videoRam = 2048; 187562306a36Sopenharmony_ci maxClock = 90000; 187662306a36Sopenharmony_ci break; 187762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 187862306a36Sopenharmony_ci videoRam = 2560; 187962306a36Sopenharmony_ci maxClock = 110000; 188062306a36Sopenharmony_ci break; 188162306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 188262306a36Sopenharmony_ci videoRam = 3008; 188362306a36Sopenharmony_ci maxClock = 110000; 188462306a36Sopenharmony_ci break; 188562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 188662306a36Sopenharmony_ci videoRam = 4096; 188762306a36Sopenharmony_ci maxClock = 110000; 188862306a36Sopenharmony_ci break; 188962306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 189062306a36Sopenharmony_ci videoRam = 6144; 189162306a36Sopenharmony_ci maxClock = 110000; 189262306a36Sopenharmony_ci break; 189362306a36Sopenharmony_ci } 189462306a36Sopenharmony_ci switch (info->fix.accel) { 189562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2070: 189662306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2090: 189762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2093: 189862306a36Sopenharmony_ci CursorOff = 0x100; 189962306a36Sopenharmony_ci break; 190062306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2097: 190162306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2160: 190262306a36Sopenharmony_ci CursorOff = 0x100; 190362306a36Sopenharmony_ci break; 190462306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 190562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 190662306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 190762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 190862306a36Sopenharmony_ci CursorOff = 0x1000; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase; 191162306a36Sopenharmony_ci break; 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci/* 191462306a36Sopenharmony_ci info->sprite.size = CursorMem; 191562306a36Sopenharmony_ci info->sprite.scan_align = 1; 191662306a36Sopenharmony_ci info->sprite.buf_align = 1; 191762306a36Sopenharmony_ci info->sprite.flags = FB_PIXMAP_IO; 191862306a36Sopenharmony_ci info->sprite.outbuf = neofb_draw_cursor; 191962306a36Sopenharmony_ci*/ 192062306a36Sopenharmony_ci par->maxClock = maxClock; 192162306a36Sopenharmony_ci par->cursorOff = CursorOff; 192262306a36Sopenharmony_ci return videoRam * 1024; 192362306a36Sopenharmony_ci} 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_cistatic struct fb_info *neo_alloc_fb_info(struct pci_dev *dev, 192762306a36Sopenharmony_ci const struct pci_device_id *id) 192862306a36Sopenharmony_ci{ 192962306a36Sopenharmony_ci struct fb_info *info; 193062306a36Sopenharmony_ci struct neofb_par *par; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci info = framebuffer_alloc(sizeof(struct neofb_par), &dev->dev); 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci if (!info) 193562306a36Sopenharmony_ci return NULL; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci par = info->par; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci info->fix.accel = id->driver_data; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci par->pci_burst = !nopciburst; 194262306a36Sopenharmony_ci par->lcd_stretch = !nostretch; 194362306a36Sopenharmony_ci par->libretto = libretto; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci par->internal_display = internal; 194662306a36Sopenharmony_ci par->external_display = external; 194762306a36Sopenharmony_ci info->flags = FBINFO_HWACCEL_YPAN; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci switch (info->fix.accel) { 195062306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2070: 195162306a36Sopenharmony_ci strscpy(info->fix.id, "MagicGraph128", sizeof(info->fix.id)); 195262306a36Sopenharmony_ci break; 195362306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2090: 195462306a36Sopenharmony_ci strscpy(info->fix.id, "MagicGraph128V", sizeof(info->fix.id)); 195562306a36Sopenharmony_ci break; 195662306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2093: 195762306a36Sopenharmony_ci strscpy(info->fix.id, "MagicGraph128ZV", sizeof(info->fix.id)); 195862306a36Sopenharmony_ci break; 195962306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2097: 196062306a36Sopenharmony_ci strscpy(info->fix.id, "Mag.Graph128ZV+", sizeof(info->fix.id)); 196162306a36Sopenharmony_ci break; 196262306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2160: 196362306a36Sopenharmony_ci strscpy(info->fix.id, "MagicGraph128XD", sizeof(info->fix.id)); 196462306a36Sopenharmony_ci break; 196562306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2200: 196662306a36Sopenharmony_ci strscpy(info->fix.id, "MagicGraph256AV", sizeof(info->fix.id)); 196762306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_IMAGEBLIT | 196862306a36Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | 196962306a36Sopenharmony_ci FBINFO_HWACCEL_FILLRECT; 197062306a36Sopenharmony_ci break; 197162306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2230: 197262306a36Sopenharmony_ci strscpy(info->fix.id, "Mag.Graph256AV+", sizeof(info->fix.id)); 197362306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_IMAGEBLIT | 197462306a36Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | 197562306a36Sopenharmony_ci FBINFO_HWACCEL_FILLRECT; 197662306a36Sopenharmony_ci break; 197762306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2360: 197862306a36Sopenharmony_ci strscpy(info->fix.id, "MagicGraph256ZX", sizeof(info->fix.id)); 197962306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_IMAGEBLIT | 198062306a36Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | 198162306a36Sopenharmony_ci FBINFO_HWACCEL_FILLRECT; 198262306a36Sopenharmony_ci break; 198362306a36Sopenharmony_ci case FB_ACCEL_NEOMAGIC_NM2380: 198462306a36Sopenharmony_ci strscpy(info->fix.id, "Mag.Graph256XL+", sizeof(info->fix.id)); 198562306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_IMAGEBLIT | 198662306a36Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | 198762306a36Sopenharmony_ci FBINFO_HWACCEL_FILLRECT; 198862306a36Sopenharmony_ci break; 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 199262306a36Sopenharmony_ci info->fix.type_aux = 0; 199362306a36Sopenharmony_ci info->fix.xpanstep = 0; 199462306a36Sopenharmony_ci info->fix.ypanstep = 4; 199562306a36Sopenharmony_ci info->fix.ywrapstep = 0; 199662306a36Sopenharmony_ci info->fix.accel = id->driver_data; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci info->fbops = &neofb_ops; 199962306a36Sopenharmony_ci info->pseudo_palette = par->palette; 200062306a36Sopenharmony_ci return info; 200162306a36Sopenharmony_ci} 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_cistatic void neo_free_fb_info(struct fb_info *info) 200462306a36Sopenharmony_ci{ 200562306a36Sopenharmony_ci if (info) { 200662306a36Sopenharmony_ci /* 200762306a36Sopenharmony_ci * Free the colourmap 200862306a36Sopenharmony_ci */ 200962306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 201062306a36Sopenharmony_ci framebuffer_release(info); 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci} 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci/* --------------------------------------------------------------------- */ 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistatic int neofb_probe(struct pci_dev *dev, const struct pci_device_id *id) 201762306a36Sopenharmony_ci{ 201862306a36Sopenharmony_ci struct fb_info *info; 201962306a36Sopenharmony_ci u_int h_sync, v_sync; 202062306a36Sopenharmony_ci int video_len, err; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci DBG("neofb_probe"); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci err = aperture_remove_conflicting_pci_devices(dev, "neofb"); 202562306a36Sopenharmony_ci if (err) 202662306a36Sopenharmony_ci return err; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci err = pci_enable_device(dev); 202962306a36Sopenharmony_ci if (err) 203062306a36Sopenharmony_ci return err; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci err = -ENOMEM; 203362306a36Sopenharmony_ci info = neo_alloc_fb_info(dev, id); 203462306a36Sopenharmony_ci if (!info) 203562306a36Sopenharmony_ci return err; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci err = neo_map_mmio(info, dev); 203862306a36Sopenharmony_ci if (err) 203962306a36Sopenharmony_ci goto err_map_mmio; 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci err = neo_scan_monitor(info); 204262306a36Sopenharmony_ci if (err) 204362306a36Sopenharmony_ci goto err_scan_monitor; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci video_len = neo_init_hw(info); 204662306a36Sopenharmony_ci if (video_len < 0) { 204762306a36Sopenharmony_ci err = video_len; 204862306a36Sopenharmony_ci goto err_init_hw; 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci err = neo_map_video(info, dev, video_len); 205262306a36Sopenharmony_ci if (err) 205362306a36Sopenharmony_ci goto err_init_hw; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci if (!fb_find_mode(&info->var, info, mode_option, NULL, 0, 205662306a36Sopenharmony_ci info->monspecs.modedb, 16)) { 205762306a36Sopenharmony_ci printk(KERN_ERR "neofb: Unable to find usable video mode.\n"); 205862306a36Sopenharmony_ci err = -EINVAL; 205962306a36Sopenharmony_ci goto err_map_video; 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci /* 206362306a36Sopenharmony_ci * Calculate the hsync and vsync frequencies. Note that 206462306a36Sopenharmony_ci * we split the 1e12 constant up so that we can preserve 206562306a36Sopenharmony_ci * the precision and fit the results into 32-bit registers. 206662306a36Sopenharmony_ci * (1953125000 * 512 = 1e12) 206762306a36Sopenharmony_ci */ 206862306a36Sopenharmony_ci h_sync = 1953125000 / info->var.pixclock; 206962306a36Sopenharmony_ci h_sync = 207062306a36Sopenharmony_ci h_sync * 512 / (info->var.xres + info->var.left_margin + 207162306a36Sopenharmony_ci info->var.right_margin + info->var.hsync_len); 207262306a36Sopenharmony_ci v_sync = 207362306a36Sopenharmony_ci h_sync / (info->var.yres + info->var.upper_margin + 207462306a36Sopenharmony_ci info->var.lower_margin + info->var.vsync_len); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci printk(KERN_INFO "neofb v" NEOFB_VERSION 207762306a36Sopenharmony_ci ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", 207862306a36Sopenharmony_ci info->fix.smem_len >> 10, info->var.xres, 207962306a36Sopenharmony_ci info->var.yres, h_sync / 1000, h_sync % 1000, v_sync); 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci err = fb_alloc_cmap(&info->cmap, 256, 0); 208262306a36Sopenharmony_ci if (err < 0) 208362306a36Sopenharmony_ci goto err_map_video; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci err = register_framebuffer(info); 208662306a36Sopenharmony_ci if (err < 0) 208762306a36Sopenharmony_ci goto err_reg_fb; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci fb_info(info, "%s frame buffer device\n", info->fix.id); 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci /* 209262306a36Sopenharmony_ci * Our driver data 209362306a36Sopenharmony_ci */ 209462306a36Sopenharmony_ci pci_set_drvdata(dev, info); 209562306a36Sopenharmony_ci return 0; 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_cierr_reg_fb: 209862306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 209962306a36Sopenharmony_cierr_map_video: 210062306a36Sopenharmony_ci neo_unmap_video(info); 210162306a36Sopenharmony_cierr_init_hw: 210262306a36Sopenharmony_ci fb_destroy_modedb(info->monspecs.modedb); 210362306a36Sopenharmony_cierr_scan_monitor: 210462306a36Sopenharmony_ci neo_unmap_mmio(info); 210562306a36Sopenharmony_cierr_map_mmio: 210662306a36Sopenharmony_ci neo_free_fb_info(info); 210762306a36Sopenharmony_ci return err; 210862306a36Sopenharmony_ci} 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_cistatic void neofb_remove(struct pci_dev *dev) 211162306a36Sopenharmony_ci{ 211262306a36Sopenharmony_ci struct fb_info *info = pci_get_drvdata(dev); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci DBG("neofb_remove"); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci if (info) { 211762306a36Sopenharmony_ci unregister_framebuffer(info); 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci neo_unmap_video(info); 212062306a36Sopenharmony_ci fb_destroy_modedb(info->monspecs.modedb); 212162306a36Sopenharmony_ci neo_unmap_mmio(info); 212262306a36Sopenharmony_ci neo_free_fb_info(info); 212362306a36Sopenharmony_ci } 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_cistatic const struct pci_device_id neofb_devices[] = { 212762306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070, 212862306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070}, 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090, 213162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090}, 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093, 213462306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093}, 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097, 213762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097}, 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160, 214062306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160}, 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200, 214362306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200}, 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230, 214662306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230}, 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360, 214962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360}, 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380, 215262306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380}, 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci {0, 0, 0, 0, 0, 0, 0} 215562306a36Sopenharmony_ci}; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, neofb_devices); 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_cistatic struct pci_driver neofb_driver = { 216062306a36Sopenharmony_ci .name = "neofb", 216162306a36Sopenharmony_ci .id_table = neofb_devices, 216262306a36Sopenharmony_ci .probe = neofb_probe, 216362306a36Sopenharmony_ci .remove = neofb_remove, 216462306a36Sopenharmony_ci}; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci/* ************************* init in-kernel code ************************** */ 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci#ifndef MODULE 216962306a36Sopenharmony_cistatic int __init neofb_setup(char *options) 217062306a36Sopenharmony_ci{ 217162306a36Sopenharmony_ci char *this_opt; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci DBG("neofb_setup"); 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci if (!options || !*options) 217662306a36Sopenharmony_ci return 0; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 217962306a36Sopenharmony_ci if (!*this_opt) 218062306a36Sopenharmony_ci continue; 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci if (!strncmp(this_opt, "internal", 8)) 218362306a36Sopenharmony_ci internal = 1; 218462306a36Sopenharmony_ci else if (!strncmp(this_opt, "external", 8)) 218562306a36Sopenharmony_ci external = 1; 218662306a36Sopenharmony_ci else if (!strncmp(this_opt, "nostretch", 9)) 218762306a36Sopenharmony_ci nostretch = 1; 218862306a36Sopenharmony_ci else if (!strncmp(this_opt, "nopciburst", 10)) 218962306a36Sopenharmony_ci nopciburst = 1; 219062306a36Sopenharmony_ci else if (!strncmp(this_opt, "libretto", 8)) 219162306a36Sopenharmony_ci libretto = 1; 219262306a36Sopenharmony_ci else 219362306a36Sopenharmony_ci mode_option = this_opt; 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci return 0; 219662306a36Sopenharmony_ci} 219762306a36Sopenharmony_ci#endif /* MODULE */ 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cistatic int __init neofb_init(void) 220062306a36Sopenharmony_ci{ 220162306a36Sopenharmony_ci#ifndef MODULE 220262306a36Sopenharmony_ci char *option = NULL; 220362306a36Sopenharmony_ci#endif 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci if (fb_modesetting_disabled("neofb")) 220662306a36Sopenharmony_ci return -ENODEV; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci#ifndef MODULE 220962306a36Sopenharmony_ci if (fb_get_options("neofb", &option)) 221062306a36Sopenharmony_ci return -ENODEV; 221162306a36Sopenharmony_ci neofb_setup(option); 221262306a36Sopenharmony_ci#endif 221362306a36Sopenharmony_ci return pci_register_driver(&neofb_driver); 221462306a36Sopenharmony_ci} 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_cimodule_init(neofb_init); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci#ifdef MODULE 221962306a36Sopenharmony_cistatic void __exit neofb_exit(void) 222062306a36Sopenharmony_ci{ 222162306a36Sopenharmony_ci pci_unregister_driver(&neofb_driver); 222262306a36Sopenharmony_ci} 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_cimodule_exit(neofb_exit); 222562306a36Sopenharmony_ci#endif /* MODULE */ 2226