162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Frame buffer driver for Trident TGUI, Blade and Image series 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro> 662306a36Sopenharmony_ci * Copyright 2009 Krzysztof Helt <krzysztof.h1@wp.pl> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * CREDITS:(in order of appearance) 962306a36Sopenharmony_ci * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video 1062306a36Sopenharmony_ci * Special thanks ;) to Mattia Crivellini <tia@mclink.it> 1162306a36Sopenharmony_ci * much inspired by the XFree86 4.x Trident driver sources 1262306a36Sopenharmony_ci * by Alan Hourihane the FreeVGA project 1362306a36Sopenharmony_ci * Francesco Salvestrini <salvestrini@users.sf.net> XP support, 1462306a36Sopenharmony_ci * code, suggestions 1562306a36Sopenharmony_ci * TODO: 1662306a36Sopenharmony_ci * timing value tweaking so it looks good on every monitor in every mode 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/aperture.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/fb.h> 2262306a36Sopenharmony_ci#include <linux/init.h> 2362306a36Sopenharmony_ci#include <linux/pci.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/delay.h> 2762306a36Sopenharmony_ci#include <video/vga.h> 2862306a36Sopenharmony_ci#include <video/trident.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <linux/i2c.h> 3162306a36Sopenharmony_ci#include <linux/i2c-algo-bit.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct tridentfb_par { 3462306a36Sopenharmony_ci void __iomem *io_virt; /* iospace virtual memory address */ 3562306a36Sopenharmony_ci u32 pseudo_pal[16]; 3662306a36Sopenharmony_ci int chip_id; 3762306a36Sopenharmony_ci int flatpanel; 3862306a36Sopenharmony_ci void (*init_accel) (struct tridentfb_par *, int, int); 3962306a36Sopenharmony_ci void (*wait_engine) (struct tridentfb_par *); 4062306a36Sopenharmony_ci void (*fill_rect) 4162306a36Sopenharmony_ci (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32); 4262306a36Sopenharmony_ci void (*copy_rect) 4362306a36Sopenharmony_ci (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32); 4462306a36Sopenharmony_ci void (*image_blit) 4562306a36Sopenharmony_ci (struct tridentfb_par *par, const char*, 4662306a36Sopenharmony_ci u32, u32, u32, u32, u32, u32); 4762306a36Sopenharmony_ci unsigned char eng_oper; /* engine operation... */ 4862306a36Sopenharmony_ci bool ddc_registered; 4962306a36Sopenharmony_ci struct i2c_adapter ddc_adapter; 5062306a36Sopenharmony_ci struct i2c_algo_bit_data ddc_algo; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic struct fb_fix_screeninfo tridentfb_fix = { 5462306a36Sopenharmony_ci .id = "Trident", 5562306a36Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 5662306a36Sopenharmony_ci .ypanstep = 1, 5762306a36Sopenharmony_ci .visual = FB_VISUAL_PSEUDOCOLOR, 5862306a36Sopenharmony_ci .accel = FB_ACCEL_NONE, 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* defaults which are normally overriden by user values */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* video mode */ 6462306a36Sopenharmony_cistatic char *mode_option; 6562306a36Sopenharmony_cistatic int bpp = 8; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int noaccel; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int center; 7062306a36Sopenharmony_cistatic int stretch; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int fp; 7362306a36Sopenharmony_cistatic int crt; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int memsize; 7662306a36Sopenharmony_cistatic int memdiff; 7762306a36Sopenharmony_cistatic int nativex; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cimodule_param(mode_option, charp, 0); 8062306a36Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); 8162306a36Sopenharmony_cimodule_param_named(mode, mode_option, charp, 0); 8262306a36Sopenharmony_ciMODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); 8362306a36Sopenharmony_cimodule_param(bpp, int, 0); 8462306a36Sopenharmony_cimodule_param(center, int, 0); 8562306a36Sopenharmony_cimodule_param(stretch, int, 0); 8662306a36Sopenharmony_cimodule_param(noaccel, int, 0); 8762306a36Sopenharmony_cimodule_param(memsize, int, 0); 8862306a36Sopenharmony_cimodule_param(memdiff, int, 0); 8962306a36Sopenharmony_cimodule_param(nativex, int, 0); 9062306a36Sopenharmony_cimodule_param(fp, int, 0); 9162306a36Sopenharmony_ciMODULE_PARM_DESC(fp, "Define if flatpanel is connected"); 9262306a36Sopenharmony_cimodule_param(crt, int, 0); 9362306a36Sopenharmony_ciMODULE_PARM_DESC(crt, "Define if CRT is connected"); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline int is_oldclock(int id) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci return (id == TGUI9440) || 9862306a36Sopenharmony_ci (id == TGUI9660) || 9962306a36Sopenharmony_ci (id == CYBER9320); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic inline int is_oldprotect(int id) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return is_oldclock(id) || 10562306a36Sopenharmony_ci (id == PROVIDIA9685) || 10662306a36Sopenharmony_ci (id == CYBER9382) || 10762306a36Sopenharmony_ci (id == CYBER9385); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic inline int is_blade(int id) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci return (id == BLADE3D) || 11362306a36Sopenharmony_ci (id == CYBERBLADEE4) || 11462306a36Sopenharmony_ci (id == CYBERBLADEi7) || 11562306a36Sopenharmony_ci (id == CYBERBLADEi7D) || 11662306a36Sopenharmony_ci (id == CYBERBLADEi1) || 11762306a36Sopenharmony_ci (id == CYBERBLADEi1D) || 11862306a36Sopenharmony_ci (id == CYBERBLADEAi1) || 11962306a36Sopenharmony_ci (id == CYBERBLADEAi1D); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic inline int is_xp(int id) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return (id == CYBERBLADEXPAi1) || 12562306a36Sopenharmony_ci (id == CYBERBLADEXPm8) || 12662306a36Sopenharmony_ci (id == CYBERBLADEXPm16); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic inline int is3Dchip(int id) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci return is_blade(id) || is_xp(id) || 13262306a36Sopenharmony_ci (id == CYBER9397) || (id == CYBER9397DVD) || 13362306a36Sopenharmony_ci (id == CYBER9520) || (id == CYBER9525DVD) || 13462306a36Sopenharmony_ci (id == IMAGE975) || (id == IMAGE985); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline int iscyber(int id) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci switch (id) { 14062306a36Sopenharmony_ci case CYBER9388: 14162306a36Sopenharmony_ci case CYBER9382: 14262306a36Sopenharmony_ci case CYBER9385: 14362306a36Sopenharmony_ci case CYBER9397: 14462306a36Sopenharmony_ci case CYBER9397DVD: 14562306a36Sopenharmony_ci case CYBER9520: 14662306a36Sopenharmony_ci case CYBER9525DVD: 14762306a36Sopenharmony_ci case CYBERBLADEE4: 14862306a36Sopenharmony_ci case CYBERBLADEi7D: 14962306a36Sopenharmony_ci case CYBERBLADEi1: 15062306a36Sopenharmony_ci case CYBERBLADEi1D: 15162306a36Sopenharmony_ci case CYBERBLADEAi1: 15262306a36Sopenharmony_ci case CYBERBLADEAi1D: 15362306a36Sopenharmony_ci case CYBERBLADEXPAi1: 15462306a36Sopenharmony_ci return 1; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci case CYBER9320: 15762306a36Sopenharmony_ci case CYBERBLADEi7: /* VIA MPV4 integrated version */ 15862306a36Sopenharmony_ci default: 15962306a36Sopenharmony_ci /* case CYBERBLDAEXPm8: Strange */ 16062306a36Sopenharmony_ci /* case CYBERBLDAEXPm16: Strange */ 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic inline void t_outb(struct tridentfb_par *p, u8 val, u16 reg) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci fb_writeb(val, p->io_virt + reg); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic inline u8 t_inb(struct tridentfb_par *p, u16 reg) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci return fb_readb(p->io_virt + reg); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic inline void writemmr(struct tridentfb_par *par, u16 r, u32 v) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci fb_writel(v, par->io_virt + r); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic inline u32 readmmr(struct tridentfb_par *par, u16 r) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return fb_readl(par->io_virt + r); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#define DDC_SDA_TGUI BIT(0) 18662306a36Sopenharmony_ci#define DDC_SCL_TGUI BIT(1) 18762306a36Sopenharmony_ci#define DDC_SCL_DRIVE_TGUI BIT(2) 18862306a36Sopenharmony_ci#define DDC_SDA_DRIVE_TGUI BIT(3) 18962306a36Sopenharmony_ci#define DDC_MASK_TGUI (DDC_SCL_DRIVE_TGUI | DDC_SDA_DRIVE_TGUI) 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void tridentfb_ddc_setscl_tgui(void *data, int val) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct tridentfb_par *par = data; 19462306a36Sopenharmony_ci u8 reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK_TGUI; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (val) 19762306a36Sopenharmony_ci reg &= ~DDC_SCL_DRIVE_TGUI; /* disable drive - don't drive hi */ 19862306a36Sopenharmony_ci else 19962306a36Sopenharmony_ci reg |= DDC_SCL_DRIVE_TGUI; /* drive low */ 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci vga_mm_wcrt(par->io_virt, I2C, reg); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void tridentfb_ddc_setsda_tgui(void *data, int val) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct tridentfb_par *par = data; 20762306a36Sopenharmony_ci u8 reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK_TGUI; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (val) 21062306a36Sopenharmony_ci reg &= ~DDC_SDA_DRIVE_TGUI; /* disable drive - don't drive hi */ 21162306a36Sopenharmony_ci else 21262306a36Sopenharmony_ci reg |= DDC_SDA_DRIVE_TGUI; /* drive low */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci vga_mm_wcrt(par->io_virt, I2C, reg); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int tridentfb_ddc_getsda_tgui(void *data) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct tridentfb_par *par = data; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SDA_TGUI); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define DDC_SDA_IN BIT(0) 22562306a36Sopenharmony_ci#define DDC_SCL_OUT BIT(1) 22662306a36Sopenharmony_ci#define DDC_SDA_OUT BIT(3) 22762306a36Sopenharmony_ci#define DDC_SCL_IN BIT(6) 22862306a36Sopenharmony_ci#define DDC_MASK (DDC_SCL_OUT | DDC_SDA_OUT) 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic void tridentfb_ddc_setscl(void *data, int val) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct tridentfb_par *par = data; 23362306a36Sopenharmony_ci unsigned char reg; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK; 23662306a36Sopenharmony_ci if (val) 23762306a36Sopenharmony_ci reg |= DDC_SCL_OUT; 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci reg &= ~DDC_SCL_OUT; 24062306a36Sopenharmony_ci vga_mm_wcrt(par->io_virt, I2C, reg); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void tridentfb_ddc_setsda(void *data, int val) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct tridentfb_par *par = data; 24662306a36Sopenharmony_ci unsigned char reg; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK; 24962306a36Sopenharmony_ci if (!val) 25062306a36Sopenharmony_ci reg |= DDC_SDA_OUT; 25162306a36Sopenharmony_ci else 25262306a36Sopenharmony_ci reg &= ~DDC_SDA_OUT; 25362306a36Sopenharmony_ci vga_mm_wcrt(par->io_virt, I2C, reg); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic int tridentfb_ddc_getscl(void *data) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct tridentfb_par *par = data; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SCL_IN); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int tridentfb_ddc_getsda(void *data) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct tridentfb_par *par = data; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SDA_IN); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int tridentfb_setup_ddc_bus(struct fb_info *info) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci strscpy(par->ddc_adapter.name, info->fix.id, 27562306a36Sopenharmony_ci sizeof(par->ddc_adapter.name)); 27662306a36Sopenharmony_ci par->ddc_adapter.owner = THIS_MODULE; 27762306a36Sopenharmony_ci par->ddc_adapter.class = I2C_CLASS_DDC; 27862306a36Sopenharmony_ci par->ddc_adapter.algo_data = &par->ddc_algo; 27962306a36Sopenharmony_ci par->ddc_adapter.dev.parent = info->device; 28062306a36Sopenharmony_ci if (is_oldclock(par->chip_id)) { /* not sure if this check is OK */ 28162306a36Sopenharmony_ci par->ddc_algo.setsda = tridentfb_ddc_setsda_tgui; 28262306a36Sopenharmony_ci par->ddc_algo.setscl = tridentfb_ddc_setscl_tgui; 28362306a36Sopenharmony_ci par->ddc_algo.getsda = tridentfb_ddc_getsda_tgui; 28462306a36Sopenharmony_ci /* no getscl */ 28562306a36Sopenharmony_ci } else { 28662306a36Sopenharmony_ci par->ddc_algo.setsda = tridentfb_ddc_setsda; 28762306a36Sopenharmony_ci par->ddc_algo.setscl = tridentfb_ddc_setscl; 28862306a36Sopenharmony_ci par->ddc_algo.getsda = tridentfb_ddc_getsda; 28962306a36Sopenharmony_ci par->ddc_algo.getscl = tridentfb_ddc_getscl; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci par->ddc_algo.udelay = 10; 29262306a36Sopenharmony_ci par->ddc_algo.timeout = 20; 29362306a36Sopenharmony_ci par->ddc_algo.data = par; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci i2c_set_adapdata(&par->ddc_adapter, par); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return i2c_bit_add_bus(&par->ddc_adapter); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* 30162306a36Sopenharmony_ci * Blade specific acceleration. 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci#define point(x, y) ((y) << 16 | (x)) 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void blade_init_accel(struct tridentfb_par *par, int pitch, int bpp) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci int v1 = (pitch >> 3) << 20; 30962306a36Sopenharmony_ci int tmp = bpp == 24 ? 2 : (bpp >> 4); 31062306a36Sopenharmony_ci int v2 = v1 | (tmp << 29); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci writemmr(par, 0x21C0, v2); 31362306a36Sopenharmony_ci writemmr(par, 0x21C4, v2); 31462306a36Sopenharmony_ci writemmr(par, 0x21B8, v2); 31562306a36Sopenharmony_ci writemmr(par, 0x21BC, v2); 31662306a36Sopenharmony_ci writemmr(par, 0x21D0, v1); 31762306a36Sopenharmony_ci writemmr(par, 0x21D4, v1); 31862306a36Sopenharmony_ci writemmr(par, 0x21C8, v1); 31962306a36Sopenharmony_ci writemmr(par, 0x21CC, v1); 32062306a36Sopenharmony_ci writemmr(par, 0x216C, 0); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void blade_wait_engine(struct tridentfb_par *par) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci while (readmmr(par, STATUS) & 0xFA800000) 32662306a36Sopenharmony_ci cpu_relax(); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void blade_fill_rect(struct tridentfb_par *par, 33062306a36Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci writemmr(par, COLOR, c); 33362306a36Sopenharmony_ci writemmr(par, ROP, rop ? ROP_X : ROP_S); 33462306a36Sopenharmony_ci writemmr(par, CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci writemmr(par, DST1, point(x, y)); 33762306a36Sopenharmony_ci writemmr(par, DST2, point(x + w - 1, y + h - 1)); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void blade_image_blit(struct tridentfb_par *par, const char *data, 34162306a36Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 b) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci unsigned size = ((w + 31) >> 5) * h; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci writemmr(par, COLOR, c); 34662306a36Sopenharmony_ci writemmr(par, BGCOLOR, b); 34762306a36Sopenharmony_ci writemmr(par, CMD, 0xa0000000 | 3 << 19); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci writemmr(par, DST1, point(x, y)); 35062306a36Sopenharmony_ci writemmr(par, DST2, point(x + w - 1, y + h - 1)); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci iowrite32_rep(par->io_virt + 0x10000, data, size); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void blade_copy_rect(struct tridentfb_par *par, 35662306a36Sopenharmony_ci u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci int direction = 2; 35962306a36Sopenharmony_ci u32 s1 = point(x1, y1); 36062306a36Sopenharmony_ci u32 s2 = point(x1 + w - 1, y1 + h - 1); 36162306a36Sopenharmony_ci u32 d1 = point(x2, y2); 36262306a36Sopenharmony_ci u32 d2 = point(x2 + w - 1, y2 + h - 1); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) 36562306a36Sopenharmony_ci direction = 0; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci writemmr(par, ROP, ROP_S); 36862306a36Sopenharmony_ci writemmr(par, CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci writemmr(par, SRC1, direction ? s2 : s1); 37162306a36Sopenharmony_ci writemmr(par, SRC2, direction ? s1 : s2); 37262306a36Sopenharmony_ci writemmr(par, DST1, direction ? d2 : d1); 37362306a36Sopenharmony_ci writemmr(par, DST2, direction ? d1 : d2); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/* 37762306a36Sopenharmony_ci * BladeXP specific acceleration functions 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void xp_init_accel(struct tridentfb_par *par, int pitch, int bpp) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci unsigned char x = bpp == 24 ? 3 : (bpp >> 4); 38362306a36Sopenharmony_ci int v1 = pitch << (bpp == 24 ? 20 : (18 + x)); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci switch (pitch << (bpp >> 3)) { 38662306a36Sopenharmony_ci case 8192: 38762306a36Sopenharmony_ci case 512: 38862306a36Sopenharmony_ci x |= 0x00; 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci case 1024: 39162306a36Sopenharmony_ci x |= 0x04; 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case 2048: 39462306a36Sopenharmony_ci x |= 0x08; 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci case 4096: 39762306a36Sopenharmony_ci x |= 0x0C; 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci t_outb(par, x, 0x2125); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci par->eng_oper = x | 0x40; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci writemmr(par, 0x2154, v1); 40662306a36Sopenharmony_ci writemmr(par, 0x2150, v1); 40762306a36Sopenharmony_ci t_outb(par, 3, 0x2126); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic void xp_wait_engine(struct tridentfb_par *par) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci int count = 0; 41362306a36Sopenharmony_ci int timeout = 0; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci while (t_inb(par, STATUS) & 0x80) { 41662306a36Sopenharmony_ci count++; 41762306a36Sopenharmony_ci if (count == 10000000) { 41862306a36Sopenharmony_ci /* Timeout */ 41962306a36Sopenharmony_ci count = 9990000; 42062306a36Sopenharmony_ci timeout++; 42162306a36Sopenharmony_ci if (timeout == 8) { 42262306a36Sopenharmony_ci /* Reset engine */ 42362306a36Sopenharmony_ci t_outb(par, 0x00, STATUS); 42462306a36Sopenharmony_ci return; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci cpu_relax(); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void xp_fill_rect(struct tridentfb_par *par, 43262306a36Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci writemmr(par, 0x2127, ROP_P); 43562306a36Sopenharmony_ci writemmr(par, 0x2158, c); 43662306a36Sopenharmony_ci writemmr(par, DRAWFL, 0x4000); 43762306a36Sopenharmony_ci writemmr(par, OLDDIM, point(h, w)); 43862306a36Sopenharmony_ci writemmr(par, OLDDST, point(y, x)); 43962306a36Sopenharmony_ci t_outb(par, 0x01, OLDCMD); 44062306a36Sopenharmony_ci t_outb(par, par->eng_oper, 0x2125); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic void xp_copy_rect(struct tridentfb_par *par, 44462306a36Sopenharmony_ci u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp; 44762306a36Sopenharmony_ci int direction = 0x0004; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if ((x1 < x2) && (y1 == y2)) { 45062306a36Sopenharmony_ci direction |= 0x0200; 45162306a36Sopenharmony_ci x1_tmp = x1 + w - 1; 45262306a36Sopenharmony_ci x2_tmp = x2 + w - 1; 45362306a36Sopenharmony_ci } else { 45462306a36Sopenharmony_ci x1_tmp = x1; 45562306a36Sopenharmony_ci x2_tmp = x2; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (y1 < y2) { 45962306a36Sopenharmony_ci direction |= 0x0100; 46062306a36Sopenharmony_ci y1_tmp = y1 + h - 1; 46162306a36Sopenharmony_ci y2_tmp = y2 + h - 1; 46262306a36Sopenharmony_ci } else { 46362306a36Sopenharmony_ci y1_tmp = y1; 46462306a36Sopenharmony_ci y2_tmp = y2; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci writemmr(par, DRAWFL, direction); 46862306a36Sopenharmony_ci t_outb(par, ROP_S, 0x2127); 46962306a36Sopenharmony_ci writemmr(par, OLDSRC, point(y1_tmp, x1_tmp)); 47062306a36Sopenharmony_ci writemmr(par, OLDDST, point(y2_tmp, x2_tmp)); 47162306a36Sopenharmony_ci writemmr(par, OLDDIM, point(h, w)); 47262306a36Sopenharmony_ci t_outb(par, 0x01, OLDCMD); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/* 47662306a36Sopenharmony_ci * Image specific acceleration functions 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistatic void image_init_accel(struct tridentfb_par *par, int pitch, int bpp) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci int tmp = bpp == 24 ? 2: (bpp >> 4); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci writemmr(par, 0x2120, 0xF0000000); 48362306a36Sopenharmony_ci writemmr(par, 0x2120, 0x40000000 | tmp); 48462306a36Sopenharmony_ci writemmr(par, 0x2120, 0x80000000); 48562306a36Sopenharmony_ci writemmr(par, 0x2144, 0x00000000); 48662306a36Sopenharmony_ci writemmr(par, 0x2148, 0x00000000); 48762306a36Sopenharmony_ci writemmr(par, 0x2150, 0x00000000); 48862306a36Sopenharmony_ci writemmr(par, 0x2154, 0x00000000); 48962306a36Sopenharmony_ci writemmr(par, 0x2120, 0x60000000 | (pitch << 16) | pitch); 49062306a36Sopenharmony_ci writemmr(par, 0x216C, 0x00000000); 49162306a36Sopenharmony_ci writemmr(par, 0x2170, 0x00000000); 49262306a36Sopenharmony_ci writemmr(par, 0x217C, 0x00000000); 49362306a36Sopenharmony_ci writemmr(par, 0x2120, 0x10000000); 49462306a36Sopenharmony_ci writemmr(par, 0x2130, (2047 << 16) | 2047); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic void image_wait_engine(struct tridentfb_par *par) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci while (readmmr(par, 0x2164) & 0xF0000000) 50062306a36Sopenharmony_ci cpu_relax(); 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic void image_fill_rect(struct tridentfb_par *par, 50462306a36Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci writemmr(par, 0x2120, 0x80000000); 50762306a36Sopenharmony_ci writemmr(par, 0x2120, 0x90000000 | ROP_S); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci writemmr(par, 0x2144, c); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci writemmr(par, DST1, point(x, y)); 51262306a36Sopenharmony_ci writemmr(par, DST2, point(x + w - 1, y + h - 1)); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci writemmr(par, 0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic void image_copy_rect(struct tridentfb_par *par, 51862306a36Sopenharmony_ci u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci int direction = 0x4; 52162306a36Sopenharmony_ci u32 s1 = point(x1, y1); 52262306a36Sopenharmony_ci u32 s2 = point(x1 + w - 1, y1 + h - 1); 52362306a36Sopenharmony_ci u32 d1 = point(x2, y2); 52462306a36Sopenharmony_ci u32 d2 = point(x2 + w - 1, y2 + h - 1); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) 52762306a36Sopenharmony_ci direction = 0; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci writemmr(par, 0x2120, 0x80000000); 53062306a36Sopenharmony_ci writemmr(par, 0x2120, 0x90000000 | ROP_S); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci writemmr(par, SRC1, direction ? s2 : s1); 53362306a36Sopenharmony_ci writemmr(par, SRC2, direction ? s1 : s2); 53462306a36Sopenharmony_ci writemmr(par, DST1, direction ? d2 : d1); 53562306a36Sopenharmony_ci writemmr(par, DST2, direction ? d1 : d2); 53662306a36Sopenharmony_ci writemmr(par, 0x2124, 53762306a36Sopenharmony_ci 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci/* 54162306a36Sopenharmony_ci * TGUI 9440/96XX acceleration 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic void tgui_init_accel(struct tridentfb_par *par, int pitch, int bpp) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci unsigned char x = bpp == 24 ? 3 : (bpp >> 4); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* disable clipping */ 54962306a36Sopenharmony_ci writemmr(par, 0x2148, 0); 55062306a36Sopenharmony_ci writemmr(par, 0x214C, point(4095, 2047)); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci switch ((pitch * bpp) / 8) { 55362306a36Sopenharmony_ci case 8192: 55462306a36Sopenharmony_ci case 512: 55562306a36Sopenharmony_ci x |= 0x00; 55662306a36Sopenharmony_ci break; 55762306a36Sopenharmony_ci case 1024: 55862306a36Sopenharmony_ci x |= 0x04; 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci case 2048: 56162306a36Sopenharmony_ci x |= 0x08; 56262306a36Sopenharmony_ci break; 56362306a36Sopenharmony_ci case 4096: 56462306a36Sopenharmony_ci x |= 0x0C; 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci fb_writew(x, par->io_virt + 0x2122); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic void tgui_fill_rect(struct tridentfb_par *par, 57262306a36Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci t_outb(par, ROP_P, 0x2127); 57562306a36Sopenharmony_ci writemmr(par, OLDCLR, c); 57662306a36Sopenharmony_ci writemmr(par, DRAWFL, 0x4020); 57762306a36Sopenharmony_ci writemmr(par, OLDDIM, point(w - 1, h - 1)); 57862306a36Sopenharmony_ci writemmr(par, OLDDST, point(x, y)); 57962306a36Sopenharmony_ci t_outb(par, 1, OLDCMD); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic void tgui_copy_rect(struct tridentfb_par *par, 58362306a36Sopenharmony_ci u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci int flags = 0; 58662306a36Sopenharmony_ci u16 x1_tmp, x2_tmp, y1_tmp, y2_tmp; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if ((x1 < x2) && (y1 == y2)) { 58962306a36Sopenharmony_ci flags |= 0x0200; 59062306a36Sopenharmony_ci x1_tmp = x1 + w - 1; 59162306a36Sopenharmony_ci x2_tmp = x2 + w - 1; 59262306a36Sopenharmony_ci } else { 59362306a36Sopenharmony_ci x1_tmp = x1; 59462306a36Sopenharmony_ci x2_tmp = x2; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (y1 < y2) { 59862306a36Sopenharmony_ci flags |= 0x0100; 59962306a36Sopenharmony_ci y1_tmp = y1 + h - 1; 60062306a36Sopenharmony_ci y2_tmp = y2 + h - 1; 60162306a36Sopenharmony_ci } else { 60262306a36Sopenharmony_ci y1_tmp = y1; 60362306a36Sopenharmony_ci y2_tmp = y2; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci writemmr(par, DRAWFL, 0x4 | flags); 60762306a36Sopenharmony_ci t_outb(par, ROP_S, 0x2127); 60862306a36Sopenharmony_ci writemmr(par, OLDSRC, point(x1_tmp, y1_tmp)); 60962306a36Sopenharmony_ci writemmr(par, OLDDST, point(x2_tmp, y2_tmp)); 61062306a36Sopenharmony_ci writemmr(par, OLDDIM, point(w - 1, h - 1)); 61162306a36Sopenharmony_ci t_outb(par, 1, OLDCMD); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/* 61562306a36Sopenharmony_ci * Accel functions called by the upper layers 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_cistatic void tridentfb_fillrect(struct fb_info *info, 61862306a36Sopenharmony_ci const struct fb_fillrect *fr) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 62162306a36Sopenharmony_ci int col; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 62462306a36Sopenharmony_ci cfb_fillrect(info, fr); 62562306a36Sopenharmony_ci return; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci if (info->var.bits_per_pixel == 8) { 62862306a36Sopenharmony_ci col = fr->color; 62962306a36Sopenharmony_ci col |= col << 8; 63062306a36Sopenharmony_ci col |= col << 16; 63162306a36Sopenharmony_ci } else 63262306a36Sopenharmony_ci col = ((u32 *)(info->pseudo_palette))[fr->color]; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci par->wait_engine(par); 63562306a36Sopenharmony_ci par->fill_rect(par, fr->dx, fr->dy, fr->width, 63662306a36Sopenharmony_ci fr->height, col, fr->rop); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic void tridentfb_imageblit(struct fb_info *info, 64062306a36Sopenharmony_ci const struct fb_image *img) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 64362306a36Sopenharmony_ci int col, bgcol; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if ((info->flags & FBINFO_HWACCEL_DISABLED) || img->depth != 1) { 64662306a36Sopenharmony_ci cfb_imageblit(info, img); 64762306a36Sopenharmony_ci return; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci if (info->var.bits_per_pixel == 8) { 65062306a36Sopenharmony_ci col = img->fg_color; 65162306a36Sopenharmony_ci col |= col << 8; 65262306a36Sopenharmony_ci col |= col << 16; 65362306a36Sopenharmony_ci bgcol = img->bg_color; 65462306a36Sopenharmony_ci bgcol |= bgcol << 8; 65562306a36Sopenharmony_ci bgcol |= bgcol << 16; 65662306a36Sopenharmony_ci } else { 65762306a36Sopenharmony_ci col = ((u32 *)(info->pseudo_palette))[img->fg_color]; 65862306a36Sopenharmony_ci bgcol = ((u32 *)(info->pseudo_palette))[img->bg_color]; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci par->wait_engine(par); 66262306a36Sopenharmony_ci if (par->image_blit) 66362306a36Sopenharmony_ci par->image_blit(par, img->data, img->dx, img->dy, 66462306a36Sopenharmony_ci img->width, img->height, col, bgcol); 66562306a36Sopenharmony_ci else 66662306a36Sopenharmony_ci cfb_imageblit(info, img); 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic void tridentfb_copyarea(struct fb_info *info, 67062306a36Sopenharmony_ci const struct fb_copyarea *ca) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 67562306a36Sopenharmony_ci cfb_copyarea(info, ca); 67662306a36Sopenharmony_ci return; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci par->wait_engine(par); 67962306a36Sopenharmony_ci par->copy_rect(par, ca->sx, ca->sy, ca->dx, ca->dy, 68062306a36Sopenharmony_ci ca->width, ca->height); 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int tridentfb_sync(struct fb_info *info) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (!(info->flags & FBINFO_HWACCEL_DISABLED)) 68862306a36Sopenharmony_ci par->wait_engine(par); 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci/* 69362306a36Sopenharmony_ci * Hardware access functions 69462306a36Sopenharmony_ci */ 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic inline unsigned char read3X4(struct tridentfb_par *par, int reg) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci return vga_mm_rcrt(par->io_virt, reg); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic inline void write3X4(struct tridentfb_par *par, int reg, 70262306a36Sopenharmony_ci unsigned char val) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci vga_mm_wcrt(par->io_virt, reg, val); 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic inline unsigned char read3CE(struct tridentfb_par *par, 70862306a36Sopenharmony_ci unsigned char reg) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci return vga_mm_rgfx(par->io_virt, reg); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic inline void writeAttr(struct tridentfb_par *par, int reg, 71462306a36Sopenharmony_ci unsigned char val) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci fb_readb(par->io_virt + VGA_IS1_RC); /* flip-flop to index */ 71762306a36Sopenharmony_ci vga_mm_wattr(par->io_virt, reg, val); 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic inline void write3CE(struct tridentfb_par *par, int reg, 72162306a36Sopenharmony_ci unsigned char val) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci vga_mm_wgfx(par->io_virt, reg, val); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic void enable_mmio(struct tridentfb_par *par) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci /* Goto New Mode */ 72962306a36Sopenharmony_ci vga_io_rseq(0x0B); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* Unprotect registers */ 73262306a36Sopenharmony_ci vga_io_wseq(NewMode1, 0x80); 73362306a36Sopenharmony_ci if (!is_oldprotect(par->chip_id)) 73462306a36Sopenharmony_ci vga_io_wseq(Protection, 0x92); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Enable MMIO */ 73762306a36Sopenharmony_ci outb(PCIReg, 0x3D4); 73862306a36Sopenharmony_ci outb(inb(0x3D5) | 0x01, 0x3D5); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic void disable_mmio(struct tridentfb_par *par) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci /* Goto New Mode */ 74462306a36Sopenharmony_ci vga_mm_rseq(par->io_virt, 0x0B); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* Unprotect registers */ 74762306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, NewMode1, 0x80); 74862306a36Sopenharmony_ci if (!is_oldprotect(par->chip_id)) 74962306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, Protection, 0x92); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Disable MMIO */ 75262306a36Sopenharmony_ci t_outb(par, PCIReg, 0x3D4); 75362306a36Sopenharmony_ci t_outb(par, t_inb(par, 0x3D5) & ~0x01, 0x3D5); 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic inline void crtc_unlock(struct tridentfb_par *par) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci write3X4(par, VGA_CRTC_V_SYNC_END, 75962306a36Sopenharmony_ci read3X4(par, VGA_CRTC_V_SYNC_END) & 0x7F); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci/* Return flat panel's maximum x resolution */ 76362306a36Sopenharmony_cistatic int get_nativex(struct tridentfb_par *par) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci int x, y, tmp; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (nativex) 76862306a36Sopenharmony_ci return nativex; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci tmp = (read3CE(par, VertStretch) >> 4) & 3; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci switch (tmp) { 77362306a36Sopenharmony_ci case 0: 77462306a36Sopenharmony_ci x = 1280; y = 1024; 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci case 2: 77762306a36Sopenharmony_ci x = 1024; y = 768; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci case 3: 78062306a36Sopenharmony_ci x = 800; y = 600; 78162306a36Sopenharmony_ci break; 78262306a36Sopenharmony_ci case 1: 78362306a36Sopenharmony_ci default: 78462306a36Sopenharmony_ci x = 640; y = 480; 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci output("%dx%d flat panel found\n", x, y); 78962306a36Sopenharmony_ci return x; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci/* Set pitch */ 79362306a36Sopenharmony_cistatic inline void set_lwidth(struct tridentfb_par *par, int width) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci write3X4(par, VGA_CRTC_OFFSET, width & 0xFF); 79662306a36Sopenharmony_ci /* chips older than TGUI9660 have only 1 width bit in AddColReg */ 79762306a36Sopenharmony_ci /* touching the other one breaks I2C/DDC */ 79862306a36Sopenharmony_ci if (par->chip_id == TGUI9440 || par->chip_id == CYBER9320) 79962306a36Sopenharmony_ci write3X4(par, AddColReg, 80062306a36Sopenharmony_ci (read3X4(par, AddColReg) & 0xEF) | ((width & 0x100) >> 4)); 80162306a36Sopenharmony_ci else 80262306a36Sopenharmony_ci write3X4(par, AddColReg, 80362306a36Sopenharmony_ci (read3X4(par, AddColReg) & 0xCF) | ((width & 0x300) >> 4)); 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/* For resolutions smaller than FP resolution stretch */ 80762306a36Sopenharmony_cistatic void screen_stretch(struct tridentfb_par *par) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci if (par->chip_id != CYBERBLADEXPAi1) 81062306a36Sopenharmony_ci write3CE(par, BiosReg, 0); 81162306a36Sopenharmony_ci else 81262306a36Sopenharmony_ci write3CE(par, BiosReg, 8); 81362306a36Sopenharmony_ci write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 1); 81462306a36Sopenharmony_ci write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 1); 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci/* For resolutions smaller than FP resolution center */ 81862306a36Sopenharmony_cistatic inline void screen_center(struct tridentfb_par *par) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 0x80); 82162306a36Sopenharmony_ci write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 0x80); 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci/* Address of first shown pixel in display memory */ 82562306a36Sopenharmony_cistatic void set_screen_start(struct tridentfb_par *par, int base) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci u8 tmp; 82862306a36Sopenharmony_ci write3X4(par, VGA_CRTC_START_LO, base & 0xFF); 82962306a36Sopenharmony_ci write3X4(par, VGA_CRTC_START_HI, (base & 0xFF00) >> 8); 83062306a36Sopenharmony_ci tmp = read3X4(par, CRTCModuleTest) & 0xDF; 83162306a36Sopenharmony_ci write3X4(par, CRTCModuleTest, tmp | ((base & 0x10000) >> 11)); 83262306a36Sopenharmony_ci tmp = read3X4(par, CRTHiOrd) & 0xF8; 83362306a36Sopenharmony_ci write3X4(par, CRTHiOrd, tmp | ((base & 0xE0000) >> 17)); 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci/* Set dotclock frequency */ 83762306a36Sopenharmony_cistatic void set_vclk(struct tridentfb_par *par, unsigned long freq) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci int m, n, k; 84062306a36Sopenharmony_ci unsigned long fi, d, di; 84162306a36Sopenharmony_ci unsigned char best_m = 0, best_n = 0, best_k = 0; 84262306a36Sopenharmony_ci unsigned char hi, lo; 84362306a36Sopenharmony_ci unsigned char shift = !is_oldclock(par->chip_id) ? 2 : 1; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci d = 20000; 84662306a36Sopenharmony_ci for (k = shift; k >= 0; k--) 84762306a36Sopenharmony_ci for (m = 1; m < 32; m++) { 84862306a36Sopenharmony_ci n = ((m + 2) << shift) - 8; 84962306a36Sopenharmony_ci for (n = (n < 0 ? 0 : n); n < 122; n++) { 85062306a36Sopenharmony_ci fi = ((14318l * (n + 8)) / (m + 2)) >> k; 85162306a36Sopenharmony_ci di = abs(fi - freq); 85262306a36Sopenharmony_ci if (di < d || (di == d && k == best_k)) { 85362306a36Sopenharmony_ci d = di; 85462306a36Sopenharmony_ci best_n = n; 85562306a36Sopenharmony_ci best_m = m; 85662306a36Sopenharmony_ci best_k = k; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci if (fi > freq) 85962306a36Sopenharmony_ci break; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (is_oldclock(par->chip_id)) { 86462306a36Sopenharmony_ci lo = best_n | (best_m << 7); 86562306a36Sopenharmony_ci hi = (best_m >> 1) | (best_k << 4); 86662306a36Sopenharmony_ci } else { 86762306a36Sopenharmony_ci lo = best_n; 86862306a36Sopenharmony_ci hi = best_m | (best_k << 6); 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (is3Dchip(par->chip_id)) { 87262306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, ClockHigh, hi); 87362306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, ClockLow, lo); 87462306a36Sopenharmony_ci } else { 87562306a36Sopenharmony_ci t_outb(par, lo, 0x43C8); 87662306a36Sopenharmony_ci t_outb(par, hi, 0x43C9); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci debug("VCLK = %X %X\n", hi, lo); 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci/* Set number of lines for flat panels*/ 88262306a36Sopenharmony_cistatic void set_number_of_lines(struct tridentfb_par *par, int lines) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci int tmp = read3CE(par, CyberEnhance) & 0x8F; 88562306a36Sopenharmony_ci if (lines > 1024) 88662306a36Sopenharmony_ci tmp |= 0x50; 88762306a36Sopenharmony_ci else if (lines > 768) 88862306a36Sopenharmony_ci tmp |= 0x30; 88962306a36Sopenharmony_ci else if (lines > 600) 89062306a36Sopenharmony_ci tmp |= 0x20; 89162306a36Sopenharmony_ci else if (lines > 480) 89262306a36Sopenharmony_ci tmp |= 0x10; 89362306a36Sopenharmony_ci write3CE(par, CyberEnhance, tmp); 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci/* 89762306a36Sopenharmony_ci * If we see that FP is active we assume we have one. 89862306a36Sopenharmony_ci * Otherwise we have a CRT display. User can override. 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_cistatic int is_flatpanel(struct tridentfb_par *par) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci if (fp) 90362306a36Sopenharmony_ci return 1; 90462306a36Sopenharmony_ci if (crt || !iscyber(par->chip_id)) 90562306a36Sopenharmony_ci return 0; 90662306a36Sopenharmony_ci return (read3CE(par, FPConfig) & 0x10) ? 1 : 0; 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci/* Try detecting the video memory size */ 91062306a36Sopenharmony_cistatic unsigned int get_memsize(struct tridentfb_par *par) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci unsigned char tmp, tmp2; 91362306a36Sopenharmony_ci unsigned int k; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci /* If memory size provided by user */ 91662306a36Sopenharmony_ci if (memsize) 91762306a36Sopenharmony_ci k = memsize * Kb; 91862306a36Sopenharmony_ci else 91962306a36Sopenharmony_ci switch (par->chip_id) { 92062306a36Sopenharmony_ci case CYBER9525DVD: 92162306a36Sopenharmony_ci k = 2560 * Kb; 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci default: 92462306a36Sopenharmony_ci tmp = read3X4(par, SPR) & 0x0F; 92562306a36Sopenharmony_ci switch (tmp) { 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci case 0x01: 92862306a36Sopenharmony_ci k = 512 * Kb; 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci case 0x02: 93162306a36Sopenharmony_ci k = 6 * Mb; /* XP */ 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci case 0x03: 93462306a36Sopenharmony_ci k = 1 * Mb; 93562306a36Sopenharmony_ci break; 93662306a36Sopenharmony_ci case 0x04: 93762306a36Sopenharmony_ci k = 8 * Mb; 93862306a36Sopenharmony_ci break; 93962306a36Sopenharmony_ci case 0x06: 94062306a36Sopenharmony_ci k = 10 * Mb; /* XP */ 94162306a36Sopenharmony_ci break; 94262306a36Sopenharmony_ci case 0x07: 94362306a36Sopenharmony_ci k = 2 * Mb; 94462306a36Sopenharmony_ci break; 94562306a36Sopenharmony_ci case 0x08: 94662306a36Sopenharmony_ci k = 12 * Mb; /* XP */ 94762306a36Sopenharmony_ci break; 94862306a36Sopenharmony_ci case 0x0A: 94962306a36Sopenharmony_ci k = 14 * Mb; /* XP */ 95062306a36Sopenharmony_ci break; 95162306a36Sopenharmony_ci case 0x0C: 95262306a36Sopenharmony_ci k = 16 * Mb; /* XP */ 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci case 0x0E: /* XP */ 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci tmp2 = vga_mm_rseq(par->io_virt, 0xC1); 95762306a36Sopenharmony_ci switch (tmp2) { 95862306a36Sopenharmony_ci case 0x00: 95962306a36Sopenharmony_ci k = 20 * Mb; 96062306a36Sopenharmony_ci break; 96162306a36Sopenharmony_ci case 0x01: 96262306a36Sopenharmony_ci k = 24 * Mb; 96362306a36Sopenharmony_ci break; 96462306a36Sopenharmony_ci case 0x10: 96562306a36Sopenharmony_ci k = 28 * Mb; 96662306a36Sopenharmony_ci break; 96762306a36Sopenharmony_ci case 0x11: 96862306a36Sopenharmony_ci k = 32 * Mb; 96962306a36Sopenharmony_ci break; 97062306a36Sopenharmony_ci default: 97162306a36Sopenharmony_ci k = 1 * Mb; 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci break; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci case 0x0F: 97762306a36Sopenharmony_ci k = 4 * Mb; 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci default: 98062306a36Sopenharmony_ci k = 1 * Mb; 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci k -= memdiff * Kb; 98662306a36Sopenharmony_ci output("framebuffer size = %d Kb\n", k / Kb); 98762306a36Sopenharmony_ci return k; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/* See if we can handle the video mode described in var */ 99162306a36Sopenharmony_cistatic int tridentfb_check_var(struct fb_var_screeninfo *var, 99262306a36Sopenharmony_ci struct fb_info *info) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 99562306a36Sopenharmony_ci int bpp = var->bits_per_pixel; 99662306a36Sopenharmony_ci int line_length; 99762306a36Sopenharmony_ci int ramdac = 230000; /* 230MHz for most 3D chips */ 99862306a36Sopenharmony_ci debug("enter\n"); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (!var->pixclock) 100162306a36Sopenharmony_ci return -EINVAL; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* check color depth */ 100462306a36Sopenharmony_ci if (bpp == 24) 100562306a36Sopenharmony_ci bpp = var->bits_per_pixel = 32; 100662306a36Sopenharmony_ci if (bpp != 8 && bpp != 16 && bpp != 32) 100762306a36Sopenharmony_ci return -EINVAL; 100862306a36Sopenharmony_ci if (par->chip_id == TGUI9440 && bpp == 32) 100962306a36Sopenharmony_ci return -EINVAL; 101062306a36Sopenharmony_ci /* check whether resolution fits on panel and in memory */ 101162306a36Sopenharmony_ci if (par->flatpanel && nativex && var->xres > nativex) 101262306a36Sopenharmony_ci return -EINVAL; 101362306a36Sopenharmony_ci /* various resolution checks */ 101462306a36Sopenharmony_ci var->xres = (var->xres + 7) & ~0x7; 101562306a36Sopenharmony_ci if (var->xres > var->xres_virtual) 101662306a36Sopenharmony_ci var->xres_virtual = var->xres; 101762306a36Sopenharmony_ci if (var->yres > var->yres_virtual) 101862306a36Sopenharmony_ci var->yres_virtual = var->yres; 101962306a36Sopenharmony_ci if (var->xres_virtual > 4095 || var->yres > 2048) 102062306a36Sopenharmony_ci return -EINVAL; 102162306a36Sopenharmony_ci /* prevent from position overflow for acceleration */ 102262306a36Sopenharmony_ci if (var->yres_virtual > 0xffff) 102362306a36Sopenharmony_ci return -EINVAL; 102462306a36Sopenharmony_ci line_length = var->xres_virtual * bpp / 8; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci if (!is3Dchip(par->chip_id) && 102762306a36Sopenharmony_ci !(info->flags & FBINFO_HWACCEL_DISABLED)) { 102862306a36Sopenharmony_ci /* acceleration requires line length to be power of 2 */ 102962306a36Sopenharmony_ci if (line_length <= 512) 103062306a36Sopenharmony_ci var->xres_virtual = 512 * 8 / bpp; 103162306a36Sopenharmony_ci else if (line_length <= 1024) 103262306a36Sopenharmony_ci var->xres_virtual = 1024 * 8 / bpp; 103362306a36Sopenharmony_ci else if (line_length <= 2048) 103462306a36Sopenharmony_ci var->xres_virtual = 2048 * 8 / bpp; 103562306a36Sopenharmony_ci else if (line_length <= 4096) 103662306a36Sopenharmony_ci var->xres_virtual = 4096 * 8 / bpp; 103762306a36Sopenharmony_ci else if (line_length <= 8192) 103862306a36Sopenharmony_ci var->xres_virtual = 8192 * 8 / bpp; 103962306a36Sopenharmony_ci else 104062306a36Sopenharmony_ci return -EINVAL; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci line_length = var->xres_virtual * bpp / 8; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* datasheet specifies how to set panning only up to 4 MB */ 104662306a36Sopenharmony_ci if (line_length * (var->yres_virtual - var->yres) > (4 << 20)) 104762306a36Sopenharmony_ci var->yres_virtual = ((4 << 20) / line_length) + var->yres; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (line_length * var->yres_virtual > info->fix.smem_len) 105062306a36Sopenharmony_ci return -EINVAL; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci switch (bpp) { 105362306a36Sopenharmony_ci case 8: 105462306a36Sopenharmony_ci var->red.offset = 0; 105562306a36Sopenharmony_ci var->red.length = 8; 105662306a36Sopenharmony_ci var->green = var->red; 105762306a36Sopenharmony_ci var->blue = var->red; 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci case 16: 106062306a36Sopenharmony_ci var->red.offset = 11; 106162306a36Sopenharmony_ci var->green.offset = 5; 106262306a36Sopenharmony_ci var->blue.offset = 0; 106362306a36Sopenharmony_ci var->red.length = 5; 106462306a36Sopenharmony_ci var->green.length = 6; 106562306a36Sopenharmony_ci var->blue.length = 5; 106662306a36Sopenharmony_ci break; 106762306a36Sopenharmony_ci case 32: 106862306a36Sopenharmony_ci var->red.offset = 16; 106962306a36Sopenharmony_ci var->green.offset = 8; 107062306a36Sopenharmony_ci var->blue.offset = 0; 107162306a36Sopenharmony_ci var->red.length = 8; 107262306a36Sopenharmony_ci var->green.length = 8; 107362306a36Sopenharmony_ci var->blue.length = 8; 107462306a36Sopenharmony_ci break; 107562306a36Sopenharmony_ci default: 107662306a36Sopenharmony_ci return -EINVAL; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (is_xp(par->chip_id)) 108062306a36Sopenharmony_ci ramdac = 350000; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci switch (par->chip_id) { 108362306a36Sopenharmony_ci case TGUI9440: 108462306a36Sopenharmony_ci ramdac = (bpp >= 16) ? 45000 : 90000; 108562306a36Sopenharmony_ci break; 108662306a36Sopenharmony_ci case CYBER9320: 108762306a36Sopenharmony_ci case TGUI9660: 108862306a36Sopenharmony_ci ramdac = 135000; 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci case PROVIDIA9685: 109162306a36Sopenharmony_ci case CYBER9388: 109262306a36Sopenharmony_ci case CYBER9382: 109362306a36Sopenharmony_ci case CYBER9385: 109462306a36Sopenharmony_ci ramdac = 170000; 109562306a36Sopenharmony_ci break; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* The clock is doubled for 32 bpp */ 109962306a36Sopenharmony_ci if (bpp == 32) 110062306a36Sopenharmony_ci ramdac /= 2; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (PICOS2KHZ(var->pixclock) > ramdac) 110362306a36Sopenharmony_ci return -EINVAL; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci debug("exit\n"); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci return 0; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci/* Pan the display */ 111262306a36Sopenharmony_cistatic int tridentfb_pan_display(struct fb_var_screeninfo *var, 111362306a36Sopenharmony_ci struct fb_info *info) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 111662306a36Sopenharmony_ci unsigned int offset; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci debug("enter\n"); 111962306a36Sopenharmony_ci offset = (var->xoffset + (var->yoffset * info->var.xres_virtual)) 112062306a36Sopenharmony_ci * info->var.bits_per_pixel / 32; 112162306a36Sopenharmony_ci set_screen_start(par, offset); 112262306a36Sopenharmony_ci debug("exit\n"); 112362306a36Sopenharmony_ci return 0; 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic inline void shadowmode_on(struct tridentfb_par *par) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci write3CE(par, CyberControl, read3CE(par, CyberControl) | 0x81); 112962306a36Sopenharmony_ci} 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci/* Set the hardware to the requested video mode */ 113262306a36Sopenharmony_cistatic int tridentfb_set_par(struct fb_info *info) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 113562306a36Sopenharmony_ci u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend; 113662306a36Sopenharmony_ci u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend; 113762306a36Sopenharmony_ci struct fb_var_screeninfo *var = &info->var; 113862306a36Sopenharmony_ci int bpp = var->bits_per_pixel; 113962306a36Sopenharmony_ci unsigned char tmp; 114062306a36Sopenharmony_ci unsigned long vclk; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci debug("enter\n"); 114362306a36Sopenharmony_ci hdispend = var->xres / 8 - 1; 114462306a36Sopenharmony_ci hsyncstart = (var->xres + var->right_margin) / 8; 114562306a36Sopenharmony_ci hsyncend = (var->xres + var->right_margin + var->hsync_len) / 8; 114662306a36Sopenharmony_ci htotal = (var->xres + var->left_margin + var->right_margin + 114762306a36Sopenharmony_ci var->hsync_len) / 8 - 5; 114862306a36Sopenharmony_ci hblankstart = hdispend + 1; 114962306a36Sopenharmony_ci hblankend = htotal + 3; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci vdispend = var->yres - 1; 115262306a36Sopenharmony_ci vsyncstart = var->yres + var->lower_margin; 115362306a36Sopenharmony_ci vsyncend = vsyncstart + var->vsync_len; 115462306a36Sopenharmony_ci vtotal = var->upper_margin + vsyncend - 2; 115562306a36Sopenharmony_ci vblankstart = vdispend + 1; 115662306a36Sopenharmony_ci vblankend = vtotal; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (info->var.vmode & FB_VMODE_INTERLACED) { 115962306a36Sopenharmony_ci vtotal /= 2; 116062306a36Sopenharmony_ci vdispend /= 2; 116162306a36Sopenharmony_ci vsyncstart /= 2; 116262306a36Sopenharmony_ci vsyncend /= 2; 116362306a36Sopenharmony_ci vblankstart /= 2; 116462306a36Sopenharmony_ci vblankend /= 2; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci enable_mmio(par); 116862306a36Sopenharmony_ci crtc_unlock(par); 116962306a36Sopenharmony_ci write3CE(par, CyberControl, 8); 117062306a36Sopenharmony_ci tmp = 0xEB; 117162306a36Sopenharmony_ci if (var->sync & FB_SYNC_HOR_HIGH_ACT) 117262306a36Sopenharmony_ci tmp &= ~0x40; 117362306a36Sopenharmony_ci if (var->sync & FB_SYNC_VERT_HIGH_ACT) 117462306a36Sopenharmony_ci tmp &= ~0x80; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci if (par->flatpanel && var->xres < nativex) { 117762306a36Sopenharmony_ci /* 117862306a36Sopenharmony_ci * on flat panels with native size larger 117962306a36Sopenharmony_ci * than requested resolution decide whether 118062306a36Sopenharmony_ci * we stretch or center 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ci t_outb(par, tmp | 0xC0, VGA_MIS_W); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci shadowmode_on(par); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (center) 118762306a36Sopenharmony_ci screen_center(par); 118862306a36Sopenharmony_ci else if (stretch) 118962306a36Sopenharmony_ci screen_stretch(par); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci } else { 119262306a36Sopenharmony_ci t_outb(par, tmp, VGA_MIS_W); 119362306a36Sopenharmony_ci write3CE(par, CyberControl, 8); 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci /* vertical timing values */ 119762306a36Sopenharmony_ci write3X4(par, VGA_CRTC_V_TOTAL, vtotal & 0xFF); 119862306a36Sopenharmony_ci write3X4(par, VGA_CRTC_V_DISP_END, vdispend & 0xFF); 119962306a36Sopenharmony_ci write3X4(par, VGA_CRTC_V_SYNC_START, vsyncstart & 0xFF); 120062306a36Sopenharmony_ci write3X4(par, VGA_CRTC_V_SYNC_END, (vsyncend & 0x0F)); 120162306a36Sopenharmony_ci write3X4(par, VGA_CRTC_V_BLANK_START, vblankstart & 0xFF); 120262306a36Sopenharmony_ci write3X4(par, VGA_CRTC_V_BLANK_END, vblankend & 0xFF); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* horizontal timing values */ 120562306a36Sopenharmony_ci write3X4(par, VGA_CRTC_H_TOTAL, htotal & 0xFF); 120662306a36Sopenharmony_ci write3X4(par, VGA_CRTC_H_DISP, hdispend & 0xFF); 120762306a36Sopenharmony_ci write3X4(par, VGA_CRTC_H_SYNC_START, hsyncstart & 0xFF); 120862306a36Sopenharmony_ci write3X4(par, VGA_CRTC_H_SYNC_END, 120962306a36Sopenharmony_ci (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); 121062306a36Sopenharmony_ci write3X4(par, VGA_CRTC_H_BLANK_START, hblankstart & 0xFF); 121162306a36Sopenharmony_ci write3X4(par, VGA_CRTC_H_BLANK_END, hblankend & 0x1F); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci /* higher bits of vertical timing values */ 121462306a36Sopenharmony_ci tmp = 0x10; 121562306a36Sopenharmony_ci if (vtotal & 0x100) tmp |= 0x01; 121662306a36Sopenharmony_ci if (vdispend & 0x100) tmp |= 0x02; 121762306a36Sopenharmony_ci if (vsyncstart & 0x100) tmp |= 0x04; 121862306a36Sopenharmony_ci if (vblankstart & 0x100) tmp |= 0x08; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (vtotal & 0x200) tmp |= 0x20; 122162306a36Sopenharmony_ci if (vdispend & 0x200) tmp |= 0x40; 122262306a36Sopenharmony_ci if (vsyncstart & 0x200) tmp |= 0x80; 122362306a36Sopenharmony_ci write3X4(par, VGA_CRTC_OVERFLOW, tmp); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci tmp = read3X4(par, CRTHiOrd) & 0x07; 122662306a36Sopenharmony_ci tmp |= 0x08; /* line compare bit 10 */ 122762306a36Sopenharmony_ci if (vtotal & 0x400) tmp |= 0x80; 122862306a36Sopenharmony_ci if (vblankstart & 0x400) tmp |= 0x40; 122962306a36Sopenharmony_ci if (vsyncstart & 0x400) tmp |= 0x20; 123062306a36Sopenharmony_ci if (vdispend & 0x400) tmp |= 0x10; 123162306a36Sopenharmony_ci write3X4(par, CRTHiOrd, tmp); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci tmp = (htotal >> 8) & 0x01; 123462306a36Sopenharmony_ci tmp |= (hdispend >> 7) & 0x02; 123562306a36Sopenharmony_ci tmp |= (hsyncstart >> 5) & 0x08; 123662306a36Sopenharmony_ci tmp |= (hblankstart >> 4) & 0x10; 123762306a36Sopenharmony_ci write3X4(par, HorizOverflow, tmp); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci tmp = 0x40; 124062306a36Sopenharmony_ci if (vblankstart & 0x200) tmp |= 0x20; 124162306a36Sopenharmony_ci//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */ 124262306a36Sopenharmony_ci write3X4(par, VGA_CRTC_MAX_SCAN, tmp); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci write3X4(par, VGA_CRTC_LINE_COMPARE, 0xFF); 124562306a36Sopenharmony_ci write3X4(par, VGA_CRTC_PRESET_ROW, 0); 124662306a36Sopenharmony_ci write3X4(par, VGA_CRTC_MODE, 0xC3); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci write3X4(par, LinearAddReg, 0x20); /* enable linear addressing */ 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80; 125162306a36Sopenharmony_ci /* enable access extended memory */ 125262306a36Sopenharmony_ci write3X4(par, CRTCModuleTest, tmp); 125362306a36Sopenharmony_ci tmp = read3CE(par, MiscIntContReg) & ~0x4; 125462306a36Sopenharmony_ci if (info->var.vmode & FB_VMODE_INTERLACED) 125562306a36Sopenharmony_ci tmp |= 0x4; 125662306a36Sopenharmony_ci write3CE(par, MiscIntContReg, tmp); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci /* enable GE for text acceleration */ 125962306a36Sopenharmony_ci write3X4(par, GraphEngReg, 0x80); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci switch (bpp) { 126262306a36Sopenharmony_ci case 8: 126362306a36Sopenharmony_ci tmp = 0x00; 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci case 16: 126662306a36Sopenharmony_ci tmp = 0x05; 126762306a36Sopenharmony_ci break; 126862306a36Sopenharmony_ci case 24: 126962306a36Sopenharmony_ci tmp = 0x29; 127062306a36Sopenharmony_ci break; 127162306a36Sopenharmony_ci case 32: 127262306a36Sopenharmony_ci tmp = 0x09; 127362306a36Sopenharmony_ci break; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci write3X4(par, PixelBusReg, tmp); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci tmp = read3X4(par, DRAMControl); 127962306a36Sopenharmony_ci if (!is_oldprotect(par->chip_id)) 128062306a36Sopenharmony_ci tmp |= 0x10; 128162306a36Sopenharmony_ci if (iscyber(par->chip_id)) 128262306a36Sopenharmony_ci tmp |= 0x20; 128362306a36Sopenharmony_ci write3X4(par, DRAMControl, tmp); /* both IO, linear enable */ 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci write3X4(par, InterfaceSel, read3X4(par, InterfaceSel) | 0x40); 128662306a36Sopenharmony_ci if (!is_xp(par->chip_id)) 128762306a36Sopenharmony_ci write3X4(par, Performance, read3X4(par, Performance) | 0x10); 128862306a36Sopenharmony_ci /* MMIO & PCI read and write burst enable */ 128962306a36Sopenharmony_ci if (par->chip_id != TGUI9440 && par->chip_id != IMAGE975) 129062306a36Sopenharmony_ci write3X4(par, PCIReg, read3X4(par, PCIReg) | 0x06); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, 0, 3); 129362306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, 1, 1); /* set char clock 8 dots wide */ 129462306a36Sopenharmony_ci /* enable 4 maps because needed in chain4 mode */ 129562306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, 2, 0x0F); 129662306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, 3, 0); 129762306a36Sopenharmony_ci vga_mm_wseq(par->io_virt, 4, 0x0E); /* memory mode enable bitmaps ?? */ 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* convert from picoseconds to kHz */ 130062306a36Sopenharmony_ci vclk = PICOS2KHZ(info->var.pixclock); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci /* divide clock by 2 if 32bpp chain4 mode display and CPU path */ 130362306a36Sopenharmony_ci tmp = read3CE(par, MiscExtFunc) & 0xF0; 130462306a36Sopenharmony_ci if (bpp == 32 || (par->chip_id == TGUI9440 && bpp == 16)) { 130562306a36Sopenharmony_ci tmp |= 8; 130662306a36Sopenharmony_ci vclk *= 2; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci set_vclk(par, vclk); 130962306a36Sopenharmony_ci write3CE(par, MiscExtFunc, tmp | 0x12); 131062306a36Sopenharmony_ci write3CE(par, 0x5, 0x40); /* no CGA compat, allow 256 col */ 131162306a36Sopenharmony_ci write3CE(par, 0x6, 0x05); /* graphics mode */ 131262306a36Sopenharmony_ci write3CE(par, 0x7, 0x0F); /* planes? */ 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci /* graphics mode and support 256 color modes */ 131562306a36Sopenharmony_ci writeAttr(par, 0x10, 0x41); 131662306a36Sopenharmony_ci writeAttr(par, 0x12, 0x0F); /* planes */ 131762306a36Sopenharmony_ci writeAttr(par, 0x13, 0); /* horizontal pel panning */ 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci /* colors */ 132062306a36Sopenharmony_ci for (tmp = 0; tmp < 0x10; tmp++) 132162306a36Sopenharmony_ci writeAttr(par, tmp, tmp); 132262306a36Sopenharmony_ci fb_readb(par->io_virt + VGA_IS1_RC); /* flip-flop to index */ 132362306a36Sopenharmony_ci t_outb(par, 0x20, VGA_ATT_W); /* enable attr */ 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci switch (bpp) { 132662306a36Sopenharmony_ci case 8: 132762306a36Sopenharmony_ci tmp = 0; 132862306a36Sopenharmony_ci break; 132962306a36Sopenharmony_ci case 16: 133062306a36Sopenharmony_ci tmp = 0x30; 133162306a36Sopenharmony_ci break; 133262306a36Sopenharmony_ci case 24: 133362306a36Sopenharmony_ci case 32: 133462306a36Sopenharmony_ci tmp = 0xD0; 133562306a36Sopenharmony_ci break; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci t_inb(par, VGA_PEL_IW); 133962306a36Sopenharmony_ci t_inb(par, VGA_PEL_MSK); 134062306a36Sopenharmony_ci t_inb(par, VGA_PEL_MSK); 134162306a36Sopenharmony_ci t_inb(par, VGA_PEL_MSK); 134262306a36Sopenharmony_ci t_inb(par, VGA_PEL_MSK); 134362306a36Sopenharmony_ci t_outb(par, tmp, VGA_PEL_MSK); 134462306a36Sopenharmony_ci t_inb(par, VGA_PEL_IW); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (par->flatpanel) 134762306a36Sopenharmony_ci set_number_of_lines(par, info->var.yres); 134862306a36Sopenharmony_ci info->fix.line_length = info->var.xres_virtual * bpp / 8; 134962306a36Sopenharmony_ci set_lwidth(par, info->fix.line_length / 8); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci if (!(info->flags & FBINFO_HWACCEL_DISABLED)) 135262306a36Sopenharmony_ci par->init_accel(par, info->var.xres_virtual, bpp); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 135562306a36Sopenharmony_ci info->cmap.len = (bpp == 8) ? 256 : 16; 135662306a36Sopenharmony_ci debug("exit\n"); 135762306a36Sopenharmony_ci return 0; 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci/* Set one color register */ 136162306a36Sopenharmony_cistatic int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, 136262306a36Sopenharmony_ci unsigned blue, unsigned transp, 136362306a36Sopenharmony_ci struct fb_info *info) 136462306a36Sopenharmony_ci{ 136562306a36Sopenharmony_ci int bpp = info->var.bits_per_pixel; 136662306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (regno >= info->cmap.len) 136962306a36Sopenharmony_ci return 1; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if (bpp == 8) { 137262306a36Sopenharmony_ci t_outb(par, 0xFF, VGA_PEL_MSK); 137362306a36Sopenharmony_ci t_outb(par, regno, VGA_PEL_IW); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci t_outb(par, red >> 10, VGA_PEL_D); 137662306a36Sopenharmony_ci t_outb(par, green >> 10, VGA_PEL_D); 137762306a36Sopenharmony_ci t_outb(par, blue >> 10, VGA_PEL_D); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci } else if (regno < 16) { 138062306a36Sopenharmony_ci if (bpp == 16) { /* RGB 565 */ 138162306a36Sopenharmony_ci u32 col; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci col = (red & 0xF800) | ((green & 0xFC00) >> 5) | 138462306a36Sopenharmony_ci ((blue & 0xF800) >> 11); 138562306a36Sopenharmony_ci col |= col << 16; 138662306a36Sopenharmony_ci ((u32 *)(info->pseudo_palette))[regno] = col; 138762306a36Sopenharmony_ci } else if (bpp == 32) /* ARGB 8888 */ 138862306a36Sopenharmony_ci ((u32 *)info->pseudo_palette)[regno] = 138962306a36Sopenharmony_ci ((transp & 0xFF00) << 16) | 139062306a36Sopenharmony_ci ((red & 0xFF00) << 8) | 139162306a36Sopenharmony_ci ((green & 0xFF00)) | 139262306a36Sopenharmony_ci ((blue & 0xFF00) >> 8); 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci return 0; 139662306a36Sopenharmony_ci} 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci/* Try blanking the screen. For flat panels it does nothing */ 139962306a36Sopenharmony_cistatic int tridentfb_blank(int blank_mode, struct fb_info *info) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci unsigned char PMCont, DPMSCont; 140262306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci debug("enter\n"); 140562306a36Sopenharmony_ci if (par->flatpanel) 140662306a36Sopenharmony_ci return 0; 140762306a36Sopenharmony_ci t_outb(par, 0x04, 0x83C8); /* Read DPMS Control */ 140862306a36Sopenharmony_ci PMCont = t_inb(par, 0x83C6) & 0xFC; 140962306a36Sopenharmony_ci DPMSCont = read3CE(par, PowerStatus) & 0xFC; 141062306a36Sopenharmony_ci switch (blank_mode) { 141162306a36Sopenharmony_ci case FB_BLANK_UNBLANK: 141262306a36Sopenharmony_ci /* Screen: On, HSync: On, VSync: On */ 141362306a36Sopenharmony_ci case FB_BLANK_NORMAL: 141462306a36Sopenharmony_ci /* Screen: Off, HSync: On, VSync: On */ 141562306a36Sopenharmony_ci PMCont |= 0x03; 141662306a36Sopenharmony_ci DPMSCont |= 0x00; 141762306a36Sopenharmony_ci break; 141862306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 141962306a36Sopenharmony_ci /* Screen: Off, HSync: Off, VSync: On */ 142062306a36Sopenharmony_ci PMCont |= 0x02; 142162306a36Sopenharmony_ci DPMSCont |= 0x01; 142262306a36Sopenharmony_ci break; 142362306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 142462306a36Sopenharmony_ci /* Screen: Off, HSync: On, VSync: Off */ 142562306a36Sopenharmony_ci PMCont |= 0x02; 142662306a36Sopenharmony_ci DPMSCont |= 0x02; 142762306a36Sopenharmony_ci break; 142862306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: 142962306a36Sopenharmony_ci /* Screen: Off, HSync: Off, VSync: Off */ 143062306a36Sopenharmony_ci PMCont |= 0x00; 143162306a36Sopenharmony_ci DPMSCont |= 0x03; 143262306a36Sopenharmony_ci break; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci write3CE(par, PowerStatus, DPMSCont); 143662306a36Sopenharmony_ci t_outb(par, 4, 0x83C8); 143762306a36Sopenharmony_ci t_outb(par, PMCont, 0x83C6); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci debug("exit\n"); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci /* let fbcon do a softblank for us */ 144262306a36Sopenharmony_ci return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic const struct fb_ops tridentfb_ops = { 144662306a36Sopenharmony_ci .owner = THIS_MODULE, 144762306a36Sopenharmony_ci .fb_setcolreg = tridentfb_setcolreg, 144862306a36Sopenharmony_ci .fb_pan_display = tridentfb_pan_display, 144962306a36Sopenharmony_ci .fb_blank = tridentfb_blank, 145062306a36Sopenharmony_ci .fb_check_var = tridentfb_check_var, 145162306a36Sopenharmony_ci .fb_set_par = tridentfb_set_par, 145262306a36Sopenharmony_ci .fb_fillrect = tridentfb_fillrect, 145362306a36Sopenharmony_ci .fb_copyarea = tridentfb_copyarea, 145462306a36Sopenharmony_ci .fb_imageblit = tridentfb_imageblit, 145562306a36Sopenharmony_ci .fb_sync = tridentfb_sync, 145662306a36Sopenharmony_ci}; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_cistatic int trident_pci_probe(struct pci_dev *dev, 145962306a36Sopenharmony_ci const struct pci_device_id *id) 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci int err; 146262306a36Sopenharmony_ci unsigned char revision; 146362306a36Sopenharmony_ci struct fb_info *info; 146462306a36Sopenharmony_ci struct tridentfb_par *default_par; 146562306a36Sopenharmony_ci int chip3D; 146662306a36Sopenharmony_ci int chip_id; 146762306a36Sopenharmony_ci bool found = false; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci err = aperture_remove_conflicting_pci_devices(dev, "tridentfb"); 147062306a36Sopenharmony_ci if (err) 147162306a36Sopenharmony_ci return err; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci err = pcim_enable_device(dev); 147462306a36Sopenharmony_ci if (err) 147562306a36Sopenharmony_ci return err; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci info = framebuffer_alloc(sizeof(struct tridentfb_par), &dev->dev); 147862306a36Sopenharmony_ci if (!info) 147962306a36Sopenharmony_ci return -ENOMEM; 148062306a36Sopenharmony_ci default_par = info->par; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci chip_id = id->device; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci /* If PCI id is 0x9660 then further detect chip type */ 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci if (chip_id == TGUI9660) { 148762306a36Sopenharmony_ci revision = vga_io_rseq(RevisionID); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci switch (revision) { 149062306a36Sopenharmony_ci case 0x21: 149162306a36Sopenharmony_ci chip_id = PROVIDIA9685; 149262306a36Sopenharmony_ci break; 149362306a36Sopenharmony_ci case 0x22: 149462306a36Sopenharmony_ci case 0x23: 149562306a36Sopenharmony_ci chip_id = CYBER9397; 149662306a36Sopenharmony_ci break; 149762306a36Sopenharmony_ci case 0x2A: 149862306a36Sopenharmony_ci chip_id = CYBER9397DVD; 149962306a36Sopenharmony_ci break; 150062306a36Sopenharmony_ci case 0x30: 150162306a36Sopenharmony_ci case 0x33: 150262306a36Sopenharmony_ci case 0x34: 150362306a36Sopenharmony_ci case 0x35: 150462306a36Sopenharmony_ci case 0x38: 150562306a36Sopenharmony_ci case 0x3A: 150662306a36Sopenharmony_ci case 0xB3: 150762306a36Sopenharmony_ci chip_id = CYBER9385; 150862306a36Sopenharmony_ci break; 150962306a36Sopenharmony_ci case 0x40 ... 0x43: 151062306a36Sopenharmony_ci chip_id = CYBER9382; 151162306a36Sopenharmony_ci break; 151262306a36Sopenharmony_ci case 0x4A: 151362306a36Sopenharmony_ci chip_id = CYBER9388; 151462306a36Sopenharmony_ci break; 151562306a36Sopenharmony_ci default: 151662306a36Sopenharmony_ci break; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci chip3D = is3Dchip(chip_id); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci if (is_xp(chip_id)) { 152362306a36Sopenharmony_ci default_par->init_accel = xp_init_accel; 152462306a36Sopenharmony_ci default_par->wait_engine = xp_wait_engine; 152562306a36Sopenharmony_ci default_par->fill_rect = xp_fill_rect; 152662306a36Sopenharmony_ci default_par->copy_rect = xp_copy_rect; 152762306a36Sopenharmony_ci tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADEXP; 152862306a36Sopenharmony_ci } else if (is_blade(chip_id)) { 152962306a36Sopenharmony_ci default_par->init_accel = blade_init_accel; 153062306a36Sopenharmony_ci default_par->wait_engine = blade_wait_engine; 153162306a36Sopenharmony_ci default_par->fill_rect = blade_fill_rect; 153262306a36Sopenharmony_ci default_par->copy_rect = blade_copy_rect; 153362306a36Sopenharmony_ci default_par->image_blit = blade_image_blit; 153462306a36Sopenharmony_ci tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADE3D; 153562306a36Sopenharmony_ci } else if (chip3D) { /* 3DImage family left */ 153662306a36Sopenharmony_ci default_par->init_accel = image_init_accel; 153762306a36Sopenharmony_ci default_par->wait_engine = image_wait_engine; 153862306a36Sopenharmony_ci default_par->fill_rect = image_fill_rect; 153962306a36Sopenharmony_ci default_par->copy_rect = image_copy_rect; 154062306a36Sopenharmony_ci tridentfb_fix.accel = FB_ACCEL_TRIDENT_3DIMAGE; 154162306a36Sopenharmony_ci } else { /* TGUI 9440/96XX family */ 154262306a36Sopenharmony_ci default_par->init_accel = tgui_init_accel; 154362306a36Sopenharmony_ci default_par->wait_engine = xp_wait_engine; 154462306a36Sopenharmony_ci default_par->fill_rect = tgui_fill_rect; 154562306a36Sopenharmony_ci default_par->copy_rect = tgui_copy_rect; 154662306a36Sopenharmony_ci tridentfb_fix.accel = FB_ACCEL_TRIDENT_TGUI; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci default_par->chip_id = chip_id; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* setup MMIO region */ 155262306a36Sopenharmony_ci tridentfb_fix.mmio_start = pci_resource_start(dev, 1); 155362306a36Sopenharmony_ci tridentfb_fix.mmio_len = pci_resource_len(dev, 1); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci if (!request_mem_region(tridentfb_fix.mmio_start, 155662306a36Sopenharmony_ci tridentfb_fix.mmio_len, "tridentfb")) { 155762306a36Sopenharmony_ci debug("request_region failed!\n"); 155862306a36Sopenharmony_ci framebuffer_release(info); 155962306a36Sopenharmony_ci return -1; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci default_par->io_virt = ioremap(tridentfb_fix.mmio_start, 156362306a36Sopenharmony_ci tridentfb_fix.mmio_len); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (!default_par->io_virt) { 156662306a36Sopenharmony_ci debug("ioremap failed\n"); 156762306a36Sopenharmony_ci err = -1; 156862306a36Sopenharmony_ci goto out_unmap1; 156962306a36Sopenharmony_ci } 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci enable_mmio(default_par); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* setup framebuffer memory */ 157462306a36Sopenharmony_ci tridentfb_fix.smem_start = pci_resource_start(dev, 0); 157562306a36Sopenharmony_ci tridentfb_fix.smem_len = get_memsize(default_par); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci if (!request_mem_region(tridentfb_fix.smem_start, 157862306a36Sopenharmony_ci tridentfb_fix.smem_len, "tridentfb")) { 157962306a36Sopenharmony_ci debug("request_mem_region failed!\n"); 158062306a36Sopenharmony_ci disable_mmio(info->par); 158162306a36Sopenharmony_ci err = -1; 158262306a36Sopenharmony_ci goto out_unmap1; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci info->screen_base = ioremap(tridentfb_fix.smem_start, 158662306a36Sopenharmony_ci tridentfb_fix.smem_len); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (!info->screen_base) { 158962306a36Sopenharmony_ci debug("ioremap failed\n"); 159062306a36Sopenharmony_ci err = -1; 159162306a36Sopenharmony_ci goto out_unmap2; 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci default_par->flatpanel = is_flatpanel(default_par); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci if (default_par->flatpanel) 159762306a36Sopenharmony_ci nativex = get_nativex(default_par); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci info->fix = tridentfb_fix; 160062306a36Sopenharmony_ci info->fbops = &tridentfb_ops; 160162306a36Sopenharmony_ci info->pseudo_palette = default_par->pseudo_pal; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci info->flags = FBINFO_HWACCEL_YPAN; 160462306a36Sopenharmony_ci if (!noaccel && default_par->init_accel) { 160562306a36Sopenharmony_ci info->flags &= ~FBINFO_HWACCEL_DISABLED; 160662306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_COPYAREA; 160762306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_FILLRECT; 160862306a36Sopenharmony_ci } else 160962306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci if (is_blade(chip_id) && chip_id != BLADE3D) 161262306a36Sopenharmony_ci info->flags |= FBINFO_READS_FAST; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci info->pixmap.addr = kmalloc(4096, GFP_KERNEL); 161562306a36Sopenharmony_ci if (!info->pixmap.addr) { 161662306a36Sopenharmony_ci err = -ENOMEM; 161762306a36Sopenharmony_ci goto out_unmap2; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci info->pixmap.size = 4096; 162162306a36Sopenharmony_ci info->pixmap.buf_align = 4; 162262306a36Sopenharmony_ci info->pixmap.scan_align = 1; 162362306a36Sopenharmony_ci info->pixmap.access_align = 32; 162462306a36Sopenharmony_ci info->pixmap.flags = FB_PIXMAP_SYSTEM; 162562306a36Sopenharmony_ci info->var.bits_per_pixel = 8; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (default_par->image_blit) { 162862306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_IMAGEBLIT; 162962306a36Sopenharmony_ci info->pixmap.scan_align = 4; 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci if (noaccel) { 163362306a36Sopenharmony_ci printk(KERN_DEBUG "disabling acceleration\n"); 163462306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 163562306a36Sopenharmony_ci info->pixmap.scan_align = 1; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci if (tridentfb_setup_ddc_bus(info) == 0) { 163962306a36Sopenharmony_ci u8 *edid = fb_ddc_read(&default_par->ddc_adapter); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci default_par->ddc_registered = true; 164262306a36Sopenharmony_ci if (edid) { 164362306a36Sopenharmony_ci fb_edid_to_monspecs(edid, &info->monspecs); 164462306a36Sopenharmony_ci kfree(edid); 164562306a36Sopenharmony_ci if (!info->monspecs.modedb) 164662306a36Sopenharmony_ci dev_err(info->device, "error getting mode database\n"); 164762306a36Sopenharmony_ci else { 164862306a36Sopenharmony_ci const struct fb_videomode *m; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci fb_videomode_to_modelist(info->monspecs.modedb, 165162306a36Sopenharmony_ci info->monspecs.modedb_len, 165262306a36Sopenharmony_ci &info->modelist); 165362306a36Sopenharmony_ci m = fb_find_best_display(&info->monspecs, 165462306a36Sopenharmony_ci &info->modelist); 165562306a36Sopenharmony_ci if (m) { 165662306a36Sopenharmony_ci fb_videomode_to_var(&info->var, m); 165762306a36Sopenharmony_ci /* fill all other info->var's fields */ 165862306a36Sopenharmony_ci if (tridentfb_check_var(&info->var, 165962306a36Sopenharmony_ci info) == 0) 166062306a36Sopenharmony_ci found = true; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if (!mode_option && !found) 166762306a36Sopenharmony_ci mode_option = "640x480-8@60"; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci /* Prepare startup mode */ 167062306a36Sopenharmony_ci if (mode_option) { 167162306a36Sopenharmony_ci err = fb_find_mode(&info->var, info, mode_option, 167262306a36Sopenharmony_ci info->monspecs.modedb, 167362306a36Sopenharmony_ci info->monspecs.modedb_len, 167462306a36Sopenharmony_ci NULL, info->var.bits_per_pixel); 167562306a36Sopenharmony_ci if (!err || err == 4) { 167662306a36Sopenharmony_ci err = -EINVAL; 167762306a36Sopenharmony_ci dev_err(info->device, "mode %s not found\n", 167862306a36Sopenharmony_ci mode_option); 167962306a36Sopenharmony_ci fb_destroy_modedb(info->monspecs.modedb); 168062306a36Sopenharmony_ci info->monspecs.modedb = NULL; 168162306a36Sopenharmony_ci goto out_unmap2; 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci fb_destroy_modedb(info->monspecs.modedb); 168662306a36Sopenharmony_ci info->monspecs.modedb = NULL; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci err = fb_alloc_cmap(&info->cmap, 256, 0); 168962306a36Sopenharmony_ci if (err < 0) 169062306a36Sopenharmony_ci goto out_unmap2; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci info->var.activate |= FB_ACTIVATE_NOW; 169362306a36Sopenharmony_ci info->device = &dev->dev; 169462306a36Sopenharmony_ci if (register_framebuffer(info) < 0) { 169562306a36Sopenharmony_ci printk(KERN_ERR "tridentfb: could not register framebuffer\n"); 169662306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 169762306a36Sopenharmony_ci err = -EINVAL; 169862306a36Sopenharmony_ci goto out_unmap2; 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci output("fb%d: %s frame buffer device %dx%d-%dbpp\n", 170162306a36Sopenharmony_ci info->node, info->fix.id, info->var.xres, 170262306a36Sopenharmony_ci info->var.yres, info->var.bits_per_pixel); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci pci_set_drvdata(dev, info); 170562306a36Sopenharmony_ci return 0; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ciout_unmap2: 170862306a36Sopenharmony_ci if (default_par->ddc_registered) 170962306a36Sopenharmony_ci i2c_del_adapter(&default_par->ddc_adapter); 171062306a36Sopenharmony_ci kfree(info->pixmap.addr); 171162306a36Sopenharmony_ci if (info->screen_base) 171262306a36Sopenharmony_ci iounmap(info->screen_base); 171362306a36Sopenharmony_ci disable_mmio(info->par); 171462306a36Sopenharmony_ciout_unmap1: 171562306a36Sopenharmony_ci if (default_par->io_virt) 171662306a36Sopenharmony_ci iounmap(default_par->io_virt); 171762306a36Sopenharmony_ci framebuffer_release(info); 171862306a36Sopenharmony_ci return err; 171962306a36Sopenharmony_ci} 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_cistatic void trident_pci_remove(struct pci_dev *dev) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci struct fb_info *info = pci_get_drvdata(dev); 172462306a36Sopenharmony_ci struct tridentfb_par *par = info->par; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci unregister_framebuffer(info); 172762306a36Sopenharmony_ci if (par->ddc_registered) 172862306a36Sopenharmony_ci i2c_del_adapter(&par->ddc_adapter); 172962306a36Sopenharmony_ci iounmap(par->io_virt); 173062306a36Sopenharmony_ci iounmap(info->screen_base); 173162306a36Sopenharmony_ci kfree(info->pixmap.addr); 173262306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 173362306a36Sopenharmony_ci framebuffer_release(info); 173462306a36Sopenharmony_ci} 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci/* List of boards that we are trying to support */ 173762306a36Sopenharmony_cistatic const struct pci_device_id trident_devices[] = { 173862306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 173962306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174062306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174162306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174262306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174362306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174462306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174562306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174662306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, TGUI9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174762306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174862306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 174962306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175062306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175162306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175262306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175362306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175462306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175562306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175662306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175762306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175862306a36Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 175962306a36Sopenharmony_ci {0,} 176062306a36Sopenharmony_ci}; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, trident_devices); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic struct pci_driver tridentfb_pci_driver = { 176562306a36Sopenharmony_ci .name = "tridentfb", 176662306a36Sopenharmony_ci .id_table = trident_devices, 176762306a36Sopenharmony_ci .probe = trident_pci_probe, 176862306a36Sopenharmony_ci .remove = trident_pci_remove, 176962306a36Sopenharmony_ci}; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci/* 177262306a36Sopenharmony_ci * Parse user specified options (`video=trident:') 177362306a36Sopenharmony_ci * example: 177462306a36Sopenharmony_ci * video=trident:800x600,bpp=16,noaccel 177562306a36Sopenharmony_ci */ 177662306a36Sopenharmony_ci#ifndef MODULE 177762306a36Sopenharmony_cistatic int __init tridentfb_setup(char *options) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci char *opt; 178062306a36Sopenharmony_ci if (!options || !*options) 178162306a36Sopenharmony_ci return 0; 178262306a36Sopenharmony_ci while ((opt = strsep(&options, ",")) != NULL) { 178362306a36Sopenharmony_ci if (!*opt) 178462306a36Sopenharmony_ci continue; 178562306a36Sopenharmony_ci if (!strncmp(opt, "noaccel", 7)) 178662306a36Sopenharmony_ci noaccel = 1; 178762306a36Sopenharmony_ci else if (!strncmp(opt, "fp", 2)) 178862306a36Sopenharmony_ci fp = 1; 178962306a36Sopenharmony_ci else if (!strncmp(opt, "crt", 3)) 179062306a36Sopenharmony_ci fp = 0; 179162306a36Sopenharmony_ci else if (!strncmp(opt, "bpp=", 4)) 179262306a36Sopenharmony_ci bpp = simple_strtoul(opt + 4, NULL, 0); 179362306a36Sopenharmony_ci else if (!strncmp(opt, "center", 6)) 179462306a36Sopenharmony_ci center = 1; 179562306a36Sopenharmony_ci else if (!strncmp(opt, "stretch", 7)) 179662306a36Sopenharmony_ci stretch = 1; 179762306a36Sopenharmony_ci else if (!strncmp(opt, "memsize=", 8)) 179862306a36Sopenharmony_ci memsize = simple_strtoul(opt + 8, NULL, 0); 179962306a36Sopenharmony_ci else if (!strncmp(opt, "memdiff=", 8)) 180062306a36Sopenharmony_ci memdiff = simple_strtoul(opt + 8, NULL, 0); 180162306a36Sopenharmony_ci else if (!strncmp(opt, "nativex=", 8)) 180262306a36Sopenharmony_ci nativex = simple_strtoul(opt + 8, NULL, 0); 180362306a36Sopenharmony_ci else 180462306a36Sopenharmony_ci mode_option = opt; 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci return 0; 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci#endif 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_cistatic int __init tridentfb_init(void) 181162306a36Sopenharmony_ci{ 181262306a36Sopenharmony_ci#ifndef MODULE 181362306a36Sopenharmony_ci char *option = NULL; 181462306a36Sopenharmony_ci#endif 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci if (fb_modesetting_disabled("tridentfb")) 181762306a36Sopenharmony_ci return -ENODEV; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci#ifndef MODULE 182062306a36Sopenharmony_ci if (fb_get_options("tridentfb", &option)) 182162306a36Sopenharmony_ci return -ENODEV; 182262306a36Sopenharmony_ci tridentfb_setup(option); 182362306a36Sopenharmony_ci#endif 182462306a36Sopenharmony_ci return pci_register_driver(&tridentfb_pci_driver); 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic void __exit tridentfb_exit(void) 182862306a36Sopenharmony_ci{ 182962306a36Sopenharmony_ci pci_unregister_driver(&tridentfb_pci_driver); 183062306a36Sopenharmony_ci} 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_cimodule_init(tridentfb_init); 183362306a36Sopenharmony_cimodule_exit(tridentfb_exit); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ciMODULE_AUTHOR("Jani Monoses <jani@iv.ro>"); 183662306a36Sopenharmony_ciMODULE_DESCRIPTION("Framebuffer driver for Trident cards"); 183762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 183862306a36Sopenharmony_ciMODULE_ALIAS("cyblafb"); 183962306a36Sopenharmony_ci 1840