18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Frame buffer driver for Trident TGUI, Blade and Image series 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro> 68c2ecf20Sopenharmony_ci * Copyright 2009 Krzysztof Helt <krzysztof.h1@wp.pl> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * CREDITS:(in order of appearance) 98c2ecf20Sopenharmony_ci * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video 108c2ecf20Sopenharmony_ci * Special thanks ;) to Mattia Crivellini <tia@mclink.it> 118c2ecf20Sopenharmony_ci * much inspired by the XFree86 4.x Trident driver sources 128c2ecf20Sopenharmony_ci * by Alan Hourihane the FreeVGA project 138c2ecf20Sopenharmony_ci * Francesco Salvestrini <salvestrini@users.sf.net> XP support, 148c2ecf20Sopenharmony_ci * code, suggestions 158c2ecf20Sopenharmony_ci * TODO: 168c2ecf20Sopenharmony_ci * timing value tweaking so it looks good on every monitor in every mode 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/fb.h> 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/delay.h> 268c2ecf20Sopenharmony_ci#include <video/vga.h> 278c2ecf20Sopenharmony_ci#include <video/trident.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/i2c.h> 308c2ecf20Sopenharmony_ci#include <linux/i2c-algo-bit.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct tridentfb_par { 338c2ecf20Sopenharmony_ci void __iomem *io_virt; /* iospace virtual memory address */ 348c2ecf20Sopenharmony_ci u32 pseudo_pal[16]; 358c2ecf20Sopenharmony_ci int chip_id; 368c2ecf20Sopenharmony_ci int flatpanel; 378c2ecf20Sopenharmony_ci void (*init_accel) (struct tridentfb_par *, int, int); 388c2ecf20Sopenharmony_ci void (*wait_engine) (struct tridentfb_par *); 398c2ecf20Sopenharmony_ci void (*fill_rect) 408c2ecf20Sopenharmony_ci (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32); 418c2ecf20Sopenharmony_ci void (*copy_rect) 428c2ecf20Sopenharmony_ci (struct tridentfb_par *par, u32, u32, u32, u32, u32, u32); 438c2ecf20Sopenharmony_ci void (*image_blit) 448c2ecf20Sopenharmony_ci (struct tridentfb_par *par, const char*, 458c2ecf20Sopenharmony_ci u32, u32, u32, u32, u32, u32); 468c2ecf20Sopenharmony_ci unsigned char eng_oper; /* engine operation... */ 478c2ecf20Sopenharmony_ci bool ddc_registered; 488c2ecf20Sopenharmony_ci struct i2c_adapter ddc_adapter; 498c2ecf20Sopenharmony_ci struct i2c_algo_bit_data ddc_algo; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic struct fb_fix_screeninfo tridentfb_fix = { 538c2ecf20Sopenharmony_ci .id = "Trident", 548c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 558c2ecf20Sopenharmony_ci .ypanstep = 1, 568c2ecf20Sopenharmony_ci .visual = FB_VISUAL_PSEUDOCOLOR, 578c2ecf20Sopenharmony_ci .accel = FB_ACCEL_NONE, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* defaults which are normally overriden by user values */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* video mode */ 638c2ecf20Sopenharmony_cistatic char *mode_option; 648c2ecf20Sopenharmony_cistatic int bpp = 8; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int noaccel; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int center; 698c2ecf20Sopenharmony_cistatic int stretch; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int fp; 728c2ecf20Sopenharmony_cistatic int crt; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int memsize; 758c2ecf20Sopenharmony_cistatic int memdiff; 768c2ecf20Sopenharmony_cistatic int nativex; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cimodule_param(mode_option, charp, 0); 798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); 808c2ecf20Sopenharmony_cimodule_param_named(mode, mode_option, charp, 0); 818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)"); 828c2ecf20Sopenharmony_cimodule_param(bpp, int, 0); 838c2ecf20Sopenharmony_cimodule_param(center, int, 0); 848c2ecf20Sopenharmony_cimodule_param(stretch, int, 0); 858c2ecf20Sopenharmony_cimodule_param(noaccel, int, 0); 868c2ecf20Sopenharmony_cimodule_param(memsize, int, 0); 878c2ecf20Sopenharmony_cimodule_param(memdiff, int, 0); 888c2ecf20Sopenharmony_cimodule_param(nativex, int, 0); 898c2ecf20Sopenharmony_cimodule_param(fp, int, 0); 908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fp, "Define if flatpanel is connected"); 918c2ecf20Sopenharmony_cimodule_param(crt, int, 0); 928c2ecf20Sopenharmony_ciMODULE_PARM_DESC(crt, "Define if CRT is connected"); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic inline int is_oldclock(int id) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return (id == TGUI9440) || 978c2ecf20Sopenharmony_ci (id == TGUI9660) || 988c2ecf20Sopenharmony_ci (id == CYBER9320); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic inline int is_oldprotect(int id) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci return is_oldclock(id) || 1048c2ecf20Sopenharmony_ci (id == PROVIDIA9685) || 1058c2ecf20Sopenharmony_ci (id == CYBER9382) || 1068c2ecf20Sopenharmony_ci (id == CYBER9385); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic inline int is_blade(int id) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci return (id == BLADE3D) || 1128c2ecf20Sopenharmony_ci (id == CYBERBLADEE4) || 1138c2ecf20Sopenharmony_ci (id == CYBERBLADEi7) || 1148c2ecf20Sopenharmony_ci (id == CYBERBLADEi7D) || 1158c2ecf20Sopenharmony_ci (id == CYBERBLADEi1) || 1168c2ecf20Sopenharmony_ci (id == CYBERBLADEi1D) || 1178c2ecf20Sopenharmony_ci (id == CYBERBLADEAi1) || 1188c2ecf20Sopenharmony_ci (id == CYBERBLADEAi1D); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic inline int is_xp(int id) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci return (id == CYBERBLADEXPAi1) || 1248c2ecf20Sopenharmony_ci (id == CYBERBLADEXPm8) || 1258c2ecf20Sopenharmony_ci (id == CYBERBLADEXPm16); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic inline int is3Dchip(int id) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci return is_blade(id) || is_xp(id) || 1318c2ecf20Sopenharmony_ci (id == CYBER9397) || (id == CYBER9397DVD) || 1328c2ecf20Sopenharmony_ci (id == CYBER9520) || (id == CYBER9525DVD) || 1338c2ecf20Sopenharmony_ci (id == IMAGE975) || (id == IMAGE985); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic inline int iscyber(int id) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci switch (id) { 1398c2ecf20Sopenharmony_ci case CYBER9388: 1408c2ecf20Sopenharmony_ci case CYBER9382: 1418c2ecf20Sopenharmony_ci case CYBER9385: 1428c2ecf20Sopenharmony_ci case CYBER9397: 1438c2ecf20Sopenharmony_ci case CYBER9397DVD: 1448c2ecf20Sopenharmony_ci case CYBER9520: 1458c2ecf20Sopenharmony_ci case CYBER9525DVD: 1468c2ecf20Sopenharmony_ci case CYBERBLADEE4: 1478c2ecf20Sopenharmony_ci case CYBERBLADEi7D: 1488c2ecf20Sopenharmony_ci case CYBERBLADEi1: 1498c2ecf20Sopenharmony_ci case CYBERBLADEi1D: 1508c2ecf20Sopenharmony_ci case CYBERBLADEAi1: 1518c2ecf20Sopenharmony_ci case CYBERBLADEAi1D: 1528c2ecf20Sopenharmony_ci case CYBERBLADEXPAi1: 1538c2ecf20Sopenharmony_ci return 1; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci case CYBER9320: 1568c2ecf20Sopenharmony_ci case CYBERBLADEi7: /* VIA MPV4 integrated version */ 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci /* case CYBERBLDAEXPm8: Strange */ 1598c2ecf20Sopenharmony_ci /* case CYBERBLDAEXPm16: Strange */ 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic inline void t_outb(struct tridentfb_par *p, u8 val, u16 reg) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci fb_writeb(val, p->io_virt + reg); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic inline u8 t_inb(struct tridentfb_par *p, u16 reg) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci return fb_readb(p->io_virt + reg); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic inline void writemmr(struct tridentfb_par *par, u16 r, u32 v) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci fb_writel(v, par->io_virt + r); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic inline u32 readmmr(struct tridentfb_par *par, u16 r) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci return fb_readl(par->io_virt + r); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define DDC_SDA_TGUI BIT(0) 1858c2ecf20Sopenharmony_ci#define DDC_SCL_TGUI BIT(1) 1868c2ecf20Sopenharmony_ci#define DDC_SCL_DRIVE_TGUI BIT(2) 1878c2ecf20Sopenharmony_ci#define DDC_SDA_DRIVE_TGUI BIT(3) 1888c2ecf20Sopenharmony_ci#define DDC_MASK_TGUI (DDC_SCL_DRIVE_TGUI | DDC_SDA_DRIVE_TGUI) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void tridentfb_ddc_setscl_tgui(void *data, int val) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct tridentfb_par *par = data; 1938c2ecf20Sopenharmony_ci u8 reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK_TGUI; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (val) 1968c2ecf20Sopenharmony_ci reg &= ~DDC_SCL_DRIVE_TGUI; /* disable drive - don't drive hi */ 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci reg |= DDC_SCL_DRIVE_TGUI; /* drive low */ 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci vga_mm_wcrt(par->io_virt, I2C, reg); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void tridentfb_ddc_setsda_tgui(void *data, int val) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct tridentfb_par *par = data; 2068c2ecf20Sopenharmony_ci u8 reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK_TGUI; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (val) 2098c2ecf20Sopenharmony_ci reg &= ~DDC_SDA_DRIVE_TGUI; /* disable drive - don't drive hi */ 2108c2ecf20Sopenharmony_ci else 2118c2ecf20Sopenharmony_ci reg |= DDC_SDA_DRIVE_TGUI; /* drive low */ 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci vga_mm_wcrt(par->io_virt, I2C, reg); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int tridentfb_ddc_getsda_tgui(void *data) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct tridentfb_par *par = data; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SDA_TGUI); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci#define DDC_SDA_IN BIT(0) 2248c2ecf20Sopenharmony_ci#define DDC_SCL_OUT BIT(1) 2258c2ecf20Sopenharmony_ci#define DDC_SDA_OUT BIT(3) 2268c2ecf20Sopenharmony_ci#define DDC_SCL_IN BIT(6) 2278c2ecf20Sopenharmony_ci#define DDC_MASK (DDC_SCL_OUT | DDC_SDA_OUT) 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic void tridentfb_ddc_setscl(void *data, int val) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct tridentfb_par *par = data; 2328c2ecf20Sopenharmony_ci unsigned char reg; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK; 2358c2ecf20Sopenharmony_ci if (val) 2368c2ecf20Sopenharmony_ci reg |= DDC_SCL_OUT; 2378c2ecf20Sopenharmony_ci else 2388c2ecf20Sopenharmony_ci reg &= ~DDC_SCL_OUT; 2398c2ecf20Sopenharmony_ci vga_mm_wcrt(par->io_virt, I2C, reg); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void tridentfb_ddc_setsda(void *data, int val) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct tridentfb_par *par = data; 2458c2ecf20Sopenharmony_ci unsigned char reg; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK; 2488c2ecf20Sopenharmony_ci if (!val) 2498c2ecf20Sopenharmony_ci reg |= DDC_SDA_OUT; 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci reg &= ~DDC_SDA_OUT; 2528c2ecf20Sopenharmony_ci vga_mm_wcrt(par->io_virt, I2C, reg); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int tridentfb_ddc_getscl(void *data) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct tridentfb_par *par = data; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SCL_IN); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int tridentfb_ddc_getsda(void *data) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct tridentfb_par *par = data; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SDA_IN); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int tridentfb_setup_ddc_bus(struct fb_info *info) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci strlcpy(par->ddc_adapter.name, info->fix.id, 2748c2ecf20Sopenharmony_ci sizeof(par->ddc_adapter.name)); 2758c2ecf20Sopenharmony_ci par->ddc_adapter.owner = THIS_MODULE; 2768c2ecf20Sopenharmony_ci par->ddc_adapter.class = I2C_CLASS_DDC; 2778c2ecf20Sopenharmony_ci par->ddc_adapter.algo_data = &par->ddc_algo; 2788c2ecf20Sopenharmony_ci par->ddc_adapter.dev.parent = info->device; 2798c2ecf20Sopenharmony_ci if (is_oldclock(par->chip_id)) { /* not sure if this check is OK */ 2808c2ecf20Sopenharmony_ci par->ddc_algo.setsda = tridentfb_ddc_setsda_tgui; 2818c2ecf20Sopenharmony_ci par->ddc_algo.setscl = tridentfb_ddc_setscl_tgui; 2828c2ecf20Sopenharmony_ci par->ddc_algo.getsda = tridentfb_ddc_getsda_tgui; 2838c2ecf20Sopenharmony_ci /* no getscl */ 2848c2ecf20Sopenharmony_ci } else { 2858c2ecf20Sopenharmony_ci par->ddc_algo.setsda = tridentfb_ddc_setsda; 2868c2ecf20Sopenharmony_ci par->ddc_algo.setscl = tridentfb_ddc_setscl; 2878c2ecf20Sopenharmony_ci par->ddc_algo.getsda = tridentfb_ddc_getsda; 2888c2ecf20Sopenharmony_ci par->ddc_algo.getscl = tridentfb_ddc_getscl; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci par->ddc_algo.udelay = 10; 2918c2ecf20Sopenharmony_ci par->ddc_algo.timeout = 20; 2928c2ecf20Sopenharmony_ci par->ddc_algo.data = par; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci i2c_set_adapdata(&par->ddc_adapter, par); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return i2c_bit_add_bus(&par->ddc_adapter); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* 3008c2ecf20Sopenharmony_ci * Blade specific acceleration. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci#define point(x, y) ((y) << 16 | (x)) 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void blade_init_accel(struct tridentfb_par *par, int pitch, int bpp) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci int v1 = (pitch >> 3) << 20; 3088c2ecf20Sopenharmony_ci int tmp = bpp == 24 ? 2 : (bpp >> 4); 3098c2ecf20Sopenharmony_ci int v2 = v1 | (tmp << 29); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci writemmr(par, 0x21C0, v2); 3128c2ecf20Sopenharmony_ci writemmr(par, 0x21C4, v2); 3138c2ecf20Sopenharmony_ci writemmr(par, 0x21B8, v2); 3148c2ecf20Sopenharmony_ci writemmr(par, 0x21BC, v2); 3158c2ecf20Sopenharmony_ci writemmr(par, 0x21D0, v1); 3168c2ecf20Sopenharmony_ci writemmr(par, 0x21D4, v1); 3178c2ecf20Sopenharmony_ci writemmr(par, 0x21C8, v1); 3188c2ecf20Sopenharmony_ci writemmr(par, 0x21CC, v1); 3198c2ecf20Sopenharmony_ci writemmr(par, 0x216C, 0); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic void blade_wait_engine(struct tridentfb_par *par) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci while (readmmr(par, STATUS) & 0xFA800000) 3258c2ecf20Sopenharmony_ci cpu_relax(); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void blade_fill_rect(struct tridentfb_par *par, 3298c2ecf20Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci writemmr(par, COLOR, c); 3328c2ecf20Sopenharmony_ci writemmr(par, ROP, rop ? ROP_X : ROP_S); 3338c2ecf20Sopenharmony_ci writemmr(par, CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci writemmr(par, DST1, point(x, y)); 3368c2ecf20Sopenharmony_ci writemmr(par, DST2, point(x + w - 1, y + h - 1)); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void blade_image_blit(struct tridentfb_par *par, const char *data, 3408c2ecf20Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 b) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci unsigned size = ((w + 31) >> 5) * h; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci writemmr(par, COLOR, c); 3458c2ecf20Sopenharmony_ci writemmr(par, BGCOLOR, b); 3468c2ecf20Sopenharmony_ci writemmr(par, CMD, 0xa0000000 | 3 << 19); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci writemmr(par, DST1, point(x, y)); 3498c2ecf20Sopenharmony_ci writemmr(par, DST2, point(x + w - 1, y + h - 1)); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci iowrite32_rep(par->io_virt + 0x10000, data, size); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic void blade_copy_rect(struct tridentfb_par *par, 3558c2ecf20Sopenharmony_ci u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int direction = 2; 3588c2ecf20Sopenharmony_ci u32 s1 = point(x1, y1); 3598c2ecf20Sopenharmony_ci u32 s2 = point(x1 + w - 1, y1 + h - 1); 3608c2ecf20Sopenharmony_ci u32 d1 = point(x2, y2); 3618c2ecf20Sopenharmony_ci u32 d2 = point(x2 + w - 1, y2 + h - 1); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) 3648c2ecf20Sopenharmony_ci direction = 0; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci writemmr(par, ROP, ROP_S); 3678c2ecf20Sopenharmony_ci writemmr(par, CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci writemmr(par, SRC1, direction ? s2 : s1); 3708c2ecf20Sopenharmony_ci writemmr(par, SRC2, direction ? s1 : s2); 3718c2ecf20Sopenharmony_ci writemmr(par, DST1, direction ? d2 : d1); 3728c2ecf20Sopenharmony_ci writemmr(par, DST2, direction ? d1 : d2); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/* 3768c2ecf20Sopenharmony_ci * BladeXP specific acceleration functions 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void xp_init_accel(struct tridentfb_par *par, int pitch, int bpp) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci unsigned char x = bpp == 24 ? 3 : (bpp >> 4); 3828c2ecf20Sopenharmony_ci int v1 = pitch << (bpp == 24 ? 20 : (18 + x)); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci switch (pitch << (bpp >> 3)) { 3858c2ecf20Sopenharmony_ci case 8192: 3868c2ecf20Sopenharmony_ci case 512: 3878c2ecf20Sopenharmony_ci x |= 0x00; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci case 1024: 3908c2ecf20Sopenharmony_ci x |= 0x04; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci case 2048: 3938c2ecf20Sopenharmony_ci x |= 0x08; 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci case 4096: 3968c2ecf20Sopenharmony_ci x |= 0x0C; 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci t_outb(par, x, 0x2125); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci par->eng_oper = x | 0x40; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci writemmr(par, 0x2154, v1); 4058c2ecf20Sopenharmony_ci writemmr(par, 0x2150, v1); 4068c2ecf20Sopenharmony_ci t_outb(par, 3, 0x2126); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void xp_wait_engine(struct tridentfb_par *par) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci int count = 0; 4128c2ecf20Sopenharmony_ci int timeout = 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci while (t_inb(par, STATUS) & 0x80) { 4158c2ecf20Sopenharmony_ci count++; 4168c2ecf20Sopenharmony_ci if (count == 10000000) { 4178c2ecf20Sopenharmony_ci /* Timeout */ 4188c2ecf20Sopenharmony_ci count = 9990000; 4198c2ecf20Sopenharmony_ci timeout++; 4208c2ecf20Sopenharmony_ci if (timeout == 8) { 4218c2ecf20Sopenharmony_ci /* Reset engine */ 4228c2ecf20Sopenharmony_ci t_outb(par, 0x00, STATUS); 4238c2ecf20Sopenharmony_ci return; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci cpu_relax(); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic void xp_fill_rect(struct tridentfb_par *par, 4318c2ecf20Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci writemmr(par, 0x2127, ROP_P); 4348c2ecf20Sopenharmony_ci writemmr(par, 0x2158, c); 4358c2ecf20Sopenharmony_ci writemmr(par, DRAWFL, 0x4000); 4368c2ecf20Sopenharmony_ci writemmr(par, OLDDIM, point(h, w)); 4378c2ecf20Sopenharmony_ci writemmr(par, OLDDST, point(y, x)); 4388c2ecf20Sopenharmony_ci t_outb(par, 0x01, OLDCMD); 4398c2ecf20Sopenharmony_ci t_outb(par, par->eng_oper, 0x2125); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void xp_copy_rect(struct tridentfb_par *par, 4438c2ecf20Sopenharmony_ci u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp; 4468c2ecf20Sopenharmony_ci int direction = 0x0004; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if ((x1 < x2) && (y1 == y2)) { 4498c2ecf20Sopenharmony_ci direction |= 0x0200; 4508c2ecf20Sopenharmony_ci x1_tmp = x1 + w - 1; 4518c2ecf20Sopenharmony_ci x2_tmp = x2 + w - 1; 4528c2ecf20Sopenharmony_ci } else { 4538c2ecf20Sopenharmony_ci x1_tmp = x1; 4548c2ecf20Sopenharmony_ci x2_tmp = x2; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (y1 < y2) { 4588c2ecf20Sopenharmony_ci direction |= 0x0100; 4598c2ecf20Sopenharmony_ci y1_tmp = y1 + h - 1; 4608c2ecf20Sopenharmony_ci y2_tmp = y2 + h - 1; 4618c2ecf20Sopenharmony_ci } else { 4628c2ecf20Sopenharmony_ci y1_tmp = y1; 4638c2ecf20Sopenharmony_ci y2_tmp = y2; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci writemmr(par, DRAWFL, direction); 4678c2ecf20Sopenharmony_ci t_outb(par, ROP_S, 0x2127); 4688c2ecf20Sopenharmony_ci writemmr(par, OLDSRC, point(y1_tmp, x1_tmp)); 4698c2ecf20Sopenharmony_ci writemmr(par, OLDDST, point(y2_tmp, x2_tmp)); 4708c2ecf20Sopenharmony_ci writemmr(par, OLDDIM, point(h, w)); 4718c2ecf20Sopenharmony_ci t_outb(par, 0x01, OLDCMD); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci/* 4758c2ecf20Sopenharmony_ci * Image specific acceleration functions 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_cistatic void image_init_accel(struct tridentfb_par *par, int pitch, int bpp) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci int tmp = bpp == 24 ? 2: (bpp >> 4); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0xF0000000); 4828c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0x40000000 | tmp); 4838c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0x80000000); 4848c2ecf20Sopenharmony_ci writemmr(par, 0x2144, 0x00000000); 4858c2ecf20Sopenharmony_ci writemmr(par, 0x2148, 0x00000000); 4868c2ecf20Sopenharmony_ci writemmr(par, 0x2150, 0x00000000); 4878c2ecf20Sopenharmony_ci writemmr(par, 0x2154, 0x00000000); 4888c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0x60000000 | (pitch << 16) | pitch); 4898c2ecf20Sopenharmony_ci writemmr(par, 0x216C, 0x00000000); 4908c2ecf20Sopenharmony_ci writemmr(par, 0x2170, 0x00000000); 4918c2ecf20Sopenharmony_ci writemmr(par, 0x217C, 0x00000000); 4928c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0x10000000); 4938c2ecf20Sopenharmony_ci writemmr(par, 0x2130, (2047 << 16) | 2047); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic void image_wait_engine(struct tridentfb_par *par) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci while (readmmr(par, 0x2164) & 0xF0000000) 4998c2ecf20Sopenharmony_ci cpu_relax(); 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic void image_fill_rect(struct tridentfb_par *par, 5038c2ecf20Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0x80000000); 5068c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0x90000000 | ROP_S); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci writemmr(par, 0x2144, c); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci writemmr(par, DST1, point(x, y)); 5118c2ecf20Sopenharmony_ci writemmr(par, DST2, point(x + w - 1, y + h - 1)); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci writemmr(par, 0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9); 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic void image_copy_rect(struct tridentfb_par *par, 5178c2ecf20Sopenharmony_ci u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci int direction = 0x4; 5208c2ecf20Sopenharmony_ci u32 s1 = point(x1, y1); 5218c2ecf20Sopenharmony_ci u32 s2 = point(x1 + w - 1, y1 + h - 1); 5228c2ecf20Sopenharmony_ci u32 d1 = point(x2, y2); 5238c2ecf20Sopenharmony_ci u32 d2 = point(x2 + w - 1, y2 + h - 1); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if ((y1 > y2) || ((y1 == y2) && (x1 > x2))) 5268c2ecf20Sopenharmony_ci direction = 0; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0x80000000); 5298c2ecf20Sopenharmony_ci writemmr(par, 0x2120, 0x90000000 | ROP_S); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci writemmr(par, SRC1, direction ? s2 : s1); 5328c2ecf20Sopenharmony_ci writemmr(par, SRC2, direction ? s1 : s2); 5338c2ecf20Sopenharmony_ci writemmr(par, DST1, direction ? d2 : d1); 5348c2ecf20Sopenharmony_ci writemmr(par, DST2, direction ? d1 : d2); 5358c2ecf20Sopenharmony_ci writemmr(par, 0x2124, 5368c2ecf20Sopenharmony_ci 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci/* 5408c2ecf20Sopenharmony_ci * TGUI 9440/96XX acceleration 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic void tgui_init_accel(struct tridentfb_par *par, int pitch, int bpp) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci unsigned char x = bpp == 24 ? 3 : (bpp >> 4); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* disable clipping */ 5488c2ecf20Sopenharmony_ci writemmr(par, 0x2148, 0); 5498c2ecf20Sopenharmony_ci writemmr(par, 0x214C, point(4095, 2047)); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci switch ((pitch * bpp) / 8) { 5528c2ecf20Sopenharmony_ci case 8192: 5538c2ecf20Sopenharmony_ci case 512: 5548c2ecf20Sopenharmony_ci x |= 0x00; 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci case 1024: 5578c2ecf20Sopenharmony_ci x |= 0x04; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci case 2048: 5608c2ecf20Sopenharmony_ci x |= 0x08; 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case 4096: 5638c2ecf20Sopenharmony_ci x |= 0x0C; 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci fb_writew(x, par->io_virt + 0x2122); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic void tgui_fill_rect(struct tridentfb_par *par, 5718c2ecf20Sopenharmony_ci u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci t_outb(par, ROP_P, 0x2127); 5748c2ecf20Sopenharmony_ci writemmr(par, OLDCLR, c); 5758c2ecf20Sopenharmony_ci writemmr(par, DRAWFL, 0x4020); 5768c2ecf20Sopenharmony_ci writemmr(par, OLDDIM, point(w - 1, h - 1)); 5778c2ecf20Sopenharmony_ci writemmr(par, OLDDST, point(x, y)); 5788c2ecf20Sopenharmony_ci t_outb(par, 1, OLDCMD); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic void tgui_copy_rect(struct tridentfb_par *par, 5828c2ecf20Sopenharmony_ci u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci int flags = 0; 5858c2ecf20Sopenharmony_ci u16 x1_tmp, x2_tmp, y1_tmp, y2_tmp; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if ((x1 < x2) && (y1 == y2)) { 5888c2ecf20Sopenharmony_ci flags |= 0x0200; 5898c2ecf20Sopenharmony_ci x1_tmp = x1 + w - 1; 5908c2ecf20Sopenharmony_ci x2_tmp = x2 + w - 1; 5918c2ecf20Sopenharmony_ci } else { 5928c2ecf20Sopenharmony_ci x1_tmp = x1; 5938c2ecf20Sopenharmony_ci x2_tmp = x2; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (y1 < y2) { 5978c2ecf20Sopenharmony_ci flags |= 0x0100; 5988c2ecf20Sopenharmony_ci y1_tmp = y1 + h - 1; 5998c2ecf20Sopenharmony_ci y2_tmp = y2 + h - 1; 6008c2ecf20Sopenharmony_ci } else { 6018c2ecf20Sopenharmony_ci y1_tmp = y1; 6028c2ecf20Sopenharmony_ci y2_tmp = y2; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci writemmr(par, DRAWFL, 0x4 | flags); 6068c2ecf20Sopenharmony_ci t_outb(par, ROP_S, 0x2127); 6078c2ecf20Sopenharmony_ci writemmr(par, OLDSRC, point(x1_tmp, y1_tmp)); 6088c2ecf20Sopenharmony_ci writemmr(par, OLDDST, point(x2_tmp, y2_tmp)); 6098c2ecf20Sopenharmony_ci writemmr(par, OLDDIM, point(w - 1, h - 1)); 6108c2ecf20Sopenharmony_ci t_outb(par, 1, OLDCMD); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/* 6148c2ecf20Sopenharmony_ci * Accel functions called by the upper layers 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_cistatic void tridentfb_fillrect(struct fb_info *info, 6178c2ecf20Sopenharmony_ci const struct fb_fillrect *fr) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 6208c2ecf20Sopenharmony_ci int col; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 6238c2ecf20Sopenharmony_ci cfb_fillrect(info, fr); 6248c2ecf20Sopenharmony_ci return; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 8) { 6278c2ecf20Sopenharmony_ci col = fr->color; 6288c2ecf20Sopenharmony_ci col |= col << 8; 6298c2ecf20Sopenharmony_ci col |= col << 16; 6308c2ecf20Sopenharmony_ci } else 6318c2ecf20Sopenharmony_ci col = ((u32 *)(info->pseudo_palette))[fr->color]; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci par->wait_engine(par); 6348c2ecf20Sopenharmony_ci par->fill_rect(par, fr->dx, fr->dy, fr->width, 6358c2ecf20Sopenharmony_ci fr->height, col, fr->rop); 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic void tridentfb_imageblit(struct fb_info *info, 6398c2ecf20Sopenharmony_ci const struct fb_image *img) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 6428c2ecf20Sopenharmony_ci int col, bgcol; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if ((info->flags & FBINFO_HWACCEL_DISABLED) || img->depth != 1) { 6458c2ecf20Sopenharmony_ci cfb_imageblit(info, img); 6468c2ecf20Sopenharmony_ci return; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 8) { 6498c2ecf20Sopenharmony_ci col = img->fg_color; 6508c2ecf20Sopenharmony_ci col |= col << 8; 6518c2ecf20Sopenharmony_ci col |= col << 16; 6528c2ecf20Sopenharmony_ci bgcol = img->bg_color; 6538c2ecf20Sopenharmony_ci bgcol |= bgcol << 8; 6548c2ecf20Sopenharmony_ci bgcol |= bgcol << 16; 6558c2ecf20Sopenharmony_ci } else { 6568c2ecf20Sopenharmony_ci col = ((u32 *)(info->pseudo_palette))[img->fg_color]; 6578c2ecf20Sopenharmony_ci bgcol = ((u32 *)(info->pseudo_palette))[img->bg_color]; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci par->wait_engine(par); 6618c2ecf20Sopenharmony_ci if (par->image_blit) 6628c2ecf20Sopenharmony_ci par->image_blit(par, img->data, img->dx, img->dy, 6638c2ecf20Sopenharmony_ci img->width, img->height, col, bgcol); 6648c2ecf20Sopenharmony_ci else 6658c2ecf20Sopenharmony_ci cfb_imageblit(info, img); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic void tridentfb_copyarea(struct fb_info *info, 6698c2ecf20Sopenharmony_ci const struct fb_copyarea *ca) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 6748c2ecf20Sopenharmony_ci cfb_copyarea(info, ca); 6758c2ecf20Sopenharmony_ci return; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci par->wait_engine(par); 6788c2ecf20Sopenharmony_ci par->copy_rect(par, ca->sx, ca->sy, ca->dx, ca->dy, 6798c2ecf20Sopenharmony_ci ca->width, ca->height); 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int tridentfb_sync(struct fb_info *info) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (!(info->flags & FBINFO_HWACCEL_DISABLED)) 6878c2ecf20Sopenharmony_ci par->wait_engine(par); 6888c2ecf20Sopenharmony_ci return 0; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci/* 6928c2ecf20Sopenharmony_ci * Hardware access functions 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic inline unsigned char read3X4(struct tridentfb_par *par, int reg) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci return vga_mm_rcrt(par->io_virt, reg); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic inline void write3X4(struct tridentfb_par *par, int reg, 7018c2ecf20Sopenharmony_ci unsigned char val) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci vga_mm_wcrt(par->io_virt, reg, val); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic inline unsigned char read3CE(struct tridentfb_par *par, 7078c2ecf20Sopenharmony_ci unsigned char reg) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci return vga_mm_rgfx(par->io_virt, reg); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic inline void writeAttr(struct tridentfb_par *par, int reg, 7138c2ecf20Sopenharmony_ci unsigned char val) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci fb_readb(par->io_virt + VGA_IS1_RC); /* flip-flop to index */ 7168c2ecf20Sopenharmony_ci vga_mm_wattr(par->io_virt, reg, val); 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic inline void write3CE(struct tridentfb_par *par, int reg, 7208c2ecf20Sopenharmony_ci unsigned char val) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci vga_mm_wgfx(par->io_virt, reg, val); 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic void enable_mmio(struct tridentfb_par *par) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci /* Goto New Mode */ 7288c2ecf20Sopenharmony_ci vga_io_rseq(0x0B); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* Unprotect registers */ 7318c2ecf20Sopenharmony_ci vga_io_wseq(NewMode1, 0x80); 7328c2ecf20Sopenharmony_ci if (!is_oldprotect(par->chip_id)) 7338c2ecf20Sopenharmony_ci vga_io_wseq(Protection, 0x92); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* Enable MMIO */ 7368c2ecf20Sopenharmony_ci outb(PCIReg, 0x3D4); 7378c2ecf20Sopenharmony_ci outb(inb(0x3D5) | 0x01, 0x3D5); 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic void disable_mmio(struct tridentfb_par *par) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci /* Goto New Mode */ 7438c2ecf20Sopenharmony_ci vga_mm_rseq(par->io_virt, 0x0B); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Unprotect registers */ 7468c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, NewMode1, 0x80); 7478c2ecf20Sopenharmony_ci if (!is_oldprotect(par->chip_id)) 7488c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, Protection, 0x92); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci /* Disable MMIO */ 7518c2ecf20Sopenharmony_ci t_outb(par, PCIReg, 0x3D4); 7528c2ecf20Sopenharmony_ci t_outb(par, t_inb(par, 0x3D5) & ~0x01, 0x3D5); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic inline void crtc_unlock(struct tridentfb_par *par) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_V_SYNC_END, 7588c2ecf20Sopenharmony_ci read3X4(par, VGA_CRTC_V_SYNC_END) & 0x7F); 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci/* Return flat panel's maximum x resolution */ 7628c2ecf20Sopenharmony_cistatic int get_nativex(struct tridentfb_par *par) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci int x, y, tmp; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (nativex) 7678c2ecf20Sopenharmony_ci return nativex; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci tmp = (read3CE(par, VertStretch) >> 4) & 3; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci switch (tmp) { 7728c2ecf20Sopenharmony_ci case 0: 7738c2ecf20Sopenharmony_ci x = 1280; y = 1024; 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci case 2: 7768c2ecf20Sopenharmony_ci x = 1024; y = 768; 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci case 3: 7798c2ecf20Sopenharmony_ci x = 800; y = 600; 7808c2ecf20Sopenharmony_ci break; 7818c2ecf20Sopenharmony_ci case 1: 7828c2ecf20Sopenharmony_ci default: 7838c2ecf20Sopenharmony_ci x = 640; y = 480; 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci output("%dx%d flat panel found\n", x, y); 7888c2ecf20Sopenharmony_ci return x; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci/* Set pitch */ 7928c2ecf20Sopenharmony_cistatic inline void set_lwidth(struct tridentfb_par *par, int width) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_OFFSET, width & 0xFF); 7958c2ecf20Sopenharmony_ci /* chips older than TGUI9660 have only 1 width bit in AddColReg */ 7968c2ecf20Sopenharmony_ci /* touching the other one breaks I2C/DDC */ 7978c2ecf20Sopenharmony_ci if (par->chip_id == TGUI9440 || par->chip_id == CYBER9320) 7988c2ecf20Sopenharmony_ci write3X4(par, AddColReg, 7998c2ecf20Sopenharmony_ci (read3X4(par, AddColReg) & 0xEF) | ((width & 0x100) >> 4)); 8008c2ecf20Sopenharmony_ci else 8018c2ecf20Sopenharmony_ci write3X4(par, AddColReg, 8028c2ecf20Sopenharmony_ci (read3X4(par, AddColReg) & 0xCF) | ((width & 0x300) >> 4)); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci/* For resolutions smaller than FP resolution stretch */ 8068c2ecf20Sopenharmony_cistatic void screen_stretch(struct tridentfb_par *par) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci if (par->chip_id != CYBERBLADEXPAi1) 8098c2ecf20Sopenharmony_ci write3CE(par, BiosReg, 0); 8108c2ecf20Sopenharmony_ci else 8118c2ecf20Sopenharmony_ci write3CE(par, BiosReg, 8); 8128c2ecf20Sopenharmony_ci write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 1); 8138c2ecf20Sopenharmony_ci write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 1); 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci/* For resolutions smaller than FP resolution center */ 8178c2ecf20Sopenharmony_cistatic inline void screen_center(struct tridentfb_par *par) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 0x80); 8208c2ecf20Sopenharmony_ci write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 0x80); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci/* Address of first shown pixel in display memory */ 8248c2ecf20Sopenharmony_cistatic void set_screen_start(struct tridentfb_par *par, int base) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci u8 tmp; 8278c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_START_LO, base & 0xFF); 8288c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_START_HI, (base & 0xFF00) >> 8); 8298c2ecf20Sopenharmony_ci tmp = read3X4(par, CRTCModuleTest) & 0xDF; 8308c2ecf20Sopenharmony_ci write3X4(par, CRTCModuleTest, tmp | ((base & 0x10000) >> 11)); 8318c2ecf20Sopenharmony_ci tmp = read3X4(par, CRTHiOrd) & 0xF8; 8328c2ecf20Sopenharmony_ci write3X4(par, CRTHiOrd, tmp | ((base & 0xE0000) >> 17)); 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci/* Set dotclock frequency */ 8368c2ecf20Sopenharmony_cistatic void set_vclk(struct tridentfb_par *par, unsigned long freq) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci int m, n, k; 8398c2ecf20Sopenharmony_ci unsigned long fi, d, di; 8408c2ecf20Sopenharmony_ci unsigned char best_m = 0, best_n = 0, best_k = 0; 8418c2ecf20Sopenharmony_ci unsigned char hi, lo; 8428c2ecf20Sopenharmony_ci unsigned char shift = !is_oldclock(par->chip_id) ? 2 : 1; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci d = 20000; 8458c2ecf20Sopenharmony_ci for (k = shift; k >= 0; k--) 8468c2ecf20Sopenharmony_ci for (m = 1; m < 32; m++) { 8478c2ecf20Sopenharmony_ci n = ((m + 2) << shift) - 8; 8488c2ecf20Sopenharmony_ci for (n = (n < 0 ? 0 : n); n < 122; n++) { 8498c2ecf20Sopenharmony_ci fi = ((14318l * (n + 8)) / (m + 2)) >> k; 8508c2ecf20Sopenharmony_ci di = abs(fi - freq); 8518c2ecf20Sopenharmony_ci if (di < d || (di == d && k == best_k)) { 8528c2ecf20Sopenharmony_ci d = di; 8538c2ecf20Sopenharmony_ci best_n = n; 8548c2ecf20Sopenharmony_ci best_m = m; 8558c2ecf20Sopenharmony_ci best_k = k; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci if (fi > freq) 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (is_oldclock(par->chip_id)) { 8638c2ecf20Sopenharmony_ci lo = best_n | (best_m << 7); 8648c2ecf20Sopenharmony_ci hi = (best_m >> 1) | (best_k << 4); 8658c2ecf20Sopenharmony_ci } else { 8668c2ecf20Sopenharmony_ci lo = best_n; 8678c2ecf20Sopenharmony_ci hi = best_m | (best_k << 6); 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (is3Dchip(par->chip_id)) { 8718c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, ClockHigh, hi); 8728c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, ClockLow, lo); 8738c2ecf20Sopenharmony_ci } else { 8748c2ecf20Sopenharmony_ci t_outb(par, lo, 0x43C8); 8758c2ecf20Sopenharmony_ci t_outb(par, hi, 0x43C9); 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci debug("VCLK = %X %X\n", hi, lo); 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci/* Set number of lines for flat panels*/ 8818c2ecf20Sopenharmony_cistatic void set_number_of_lines(struct tridentfb_par *par, int lines) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci int tmp = read3CE(par, CyberEnhance) & 0x8F; 8848c2ecf20Sopenharmony_ci if (lines > 1024) 8858c2ecf20Sopenharmony_ci tmp |= 0x50; 8868c2ecf20Sopenharmony_ci else if (lines > 768) 8878c2ecf20Sopenharmony_ci tmp |= 0x30; 8888c2ecf20Sopenharmony_ci else if (lines > 600) 8898c2ecf20Sopenharmony_ci tmp |= 0x20; 8908c2ecf20Sopenharmony_ci else if (lines > 480) 8918c2ecf20Sopenharmony_ci tmp |= 0x10; 8928c2ecf20Sopenharmony_ci write3CE(par, CyberEnhance, tmp); 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci/* 8968c2ecf20Sopenharmony_ci * If we see that FP is active we assume we have one. 8978c2ecf20Sopenharmony_ci * Otherwise we have a CRT display. User can override. 8988c2ecf20Sopenharmony_ci */ 8998c2ecf20Sopenharmony_cistatic int is_flatpanel(struct tridentfb_par *par) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci if (fp) 9028c2ecf20Sopenharmony_ci return 1; 9038c2ecf20Sopenharmony_ci if (crt || !iscyber(par->chip_id)) 9048c2ecf20Sopenharmony_ci return 0; 9058c2ecf20Sopenharmony_ci return (read3CE(par, FPConfig) & 0x10) ? 1 : 0; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* Try detecting the video memory size */ 9098c2ecf20Sopenharmony_cistatic unsigned int get_memsize(struct tridentfb_par *par) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci unsigned char tmp, tmp2; 9128c2ecf20Sopenharmony_ci unsigned int k; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci /* If memory size provided by user */ 9158c2ecf20Sopenharmony_ci if (memsize) 9168c2ecf20Sopenharmony_ci k = memsize * Kb; 9178c2ecf20Sopenharmony_ci else 9188c2ecf20Sopenharmony_ci switch (par->chip_id) { 9198c2ecf20Sopenharmony_ci case CYBER9525DVD: 9208c2ecf20Sopenharmony_ci k = 2560 * Kb; 9218c2ecf20Sopenharmony_ci break; 9228c2ecf20Sopenharmony_ci default: 9238c2ecf20Sopenharmony_ci tmp = read3X4(par, SPR) & 0x0F; 9248c2ecf20Sopenharmony_ci switch (tmp) { 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci case 0x01: 9278c2ecf20Sopenharmony_ci k = 512 * Kb; 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci case 0x02: 9308c2ecf20Sopenharmony_ci k = 6 * Mb; /* XP */ 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci case 0x03: 9338c2ecf20Sopenharmony_ci k = 1 * Mb; 9348c2ecf20Sopenharmony_ci break; 9358c2ecf20Sopenharmony_ci case 0x04: 9368c2ecf20Sopenharmony_ci k = 8 * Mb; 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci case 0x06: 9398c2ecf20Sopenharmony_ci k = 10 * Mb; /* XP */ 9408c2ecf20Sopenharmony_ci break; 9418c2ecf20Sopenharmony_ci case 0x07: 9428c2ecf20Sopenharmony_ci k = 2 * Mb; 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci case 0x08: 9458c2ecf20Sopenharmony_ci k = 12 * Mb; /* XP */ 9468c2ecf20Sopenharmony_ci break; 9478c2ecf20Sopenharmony_ci case 0x0A: 9488c2ecf20Sopenharmony_ci k = 14 * Mb; /* XP */ 9498c2ecf20Sopenharmony_ci break; 9508c2ecf20Sopenharmony_ci case 0x0C: 9518c2ecf20Sopenharmony_ci k = 16 * Mb; /* XP */ 9528c2ecf20Sopenharmony_ci break; 9538c2ecf20Sopenharmony_ci case 0x0E: /* XP */ 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci tmp2 = vga_mm_rseq(par->io_virt, 0xC1); 9568c2ecf20Sopenharmony_ci switch (tmp2) { 9578c2ecf20Sopenharmony_ci case 0x00: 9588c2ecf20Sopenharmony_ci k = 20 * Mb; 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci case 0x01: 9618c2ecf20Sopenharmony_ci k = 24 * Mb; 9628c2ecf20Sopenharmony_ci break; 9638c2ecf20Sopenharmony_ci case 0x10: 9648c2ecf20Sopenharmony_ci k = 28 * Mb; 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci case 0x11: 9678c2ecf20Sopenharmony_ci k = 32 * Mb; 9688c2ecf20Sopenharmony_ci break; 9698c2ecf20Sopenharmony_ci default: 9708c2ecf20Sopenharmony_ci k = 1 * Mb; 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci break; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci case 0x0F: 9768c2ecf20Sopenharmony_ci k = 4 * Mb; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci default: 9798c2ecf20Sopenharmony_ci k = 1 * Mb; 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci k -= memdiff * Kb; 9858c2ecf20Sopenharmony_ci output("framebuffer size = %d Kb\n", k / Kb); 9868c2ecf20Sopenharmony_ci return k; 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci/* See if we can handle the video mode described in var */ 9908c2ecf20Sopenharmony_cistatic int tridentfb_check_var(struct fb_var_screeninfo *var, 9918c2ecf20Sopenharmony_ci struct fb_info *info) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 9948c2ecf20Sopenharmony_ci int bpp = var->bits_per_pixel; 9958c2ecf20Sopenharmony_ci int line_length; 9968c2ecf20Sopenharmony_ci int ramdac = 230000; /* 230MHz for most 3D chips */ 9978c2ecf20Sopenharmony_ci debug("enter\n"); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* check color depth */ 10008c2ecf20Sopenharmony_ci if (bpp == 24) 10018c2ecf20Sopenharmony_ci bpp = var->bits_per_pixel = 32; 10028c2ecf20Sopenharmony_ci if (bpp != 8 && bpp != 16 && bpp != 32) 10038c2ecf20Sopenharmony_ci return -EINVAL; 10048c2ecf20Sopenharmony_ci if (par->chip_id == TGUI9440 && bpp == 32) 10058c2ecf20Sopenharmony_ci return -EINVAL; 10068c2ecf20Sopenharmony_ci /* check whether resolution fits on panel and in memory */ 10078c2ecf20Sopenharmony_ci if (par->flatpanel && nativex && var->xres > nativex) 10088c2ecf20Sopenharmony_ci return -EINVAL; 10098c2ecf20Sopenharmony_ci /* various resolution checks */ 10108c2ecf20Sopenharmony_ci var->xres = (var->xres + 7) & ~0x7; 10118c2ecf20Sopenharmony_ci if (var->xres > var->xres_virtual) 10128c2ecf20Sopenharmony_ci var->xres_virtual = var->xres; 10138c2ecf20Sopenharmony_ci if (var->yres > var->yres_virtual) 10148c2ecf20Sopenharmony_ci var->yres_virtual = var->yres; 10158c2ecf20Sopenharmony_ci if (var->xres_virtual > 4095 || var->yres > 2048) 10168c2ecf20Sopenharmony_ci return -EINVAL; 10178c2ecf20Sopenharmony_ci /* prevent from position overflow for acceleration */ 10188c2ecf20Sopenharmony_ci if (var->yres_virtual > 0xffff) 10198c2ecf20Sopenharmony_ci return -EINVAL; 10208c2ecf20Sopenharmony_ci line_length = var->xres_virtual * bpp / 8; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (!is3Dchip(par->chip_id) && 10238c2ecf20Sopenharmony_ci !(info->flags & FBINFO_HWACCEL_DISABLED)) { 10248c2ecf20Sopenharmony_ci /* acceleration requires line length to be power of 2 */ 10258c2ecf20Sopenharmony_ci if (line_length <= 512) 10268c2ecf20Sopenharmony_ci var->xres_virtual = 512 * 8 / bpp; 10278c2ecf20Sopenharmony_ci else if (line_length <= 1024) 10288c2ecf20Sopenharmony_ci var->xres_virtual = 1024 * 8 / bpp; 10298c2ecf20Sopenharmony_ci else if (line_length <= 2048) 10308c2ecf20Sopenharmony_ci var->xres_virtual = 2048 * 8 / bpp; 10318c2ecf20Sopenharmony_ci else if (line_length <= 4096) 10328c2ecf20Sopenharmony_ci var->xres_virtual = 4096 * 8 / bpp; 10338c2ecf20Sopenharmony_ci else if (line_length <= 8192) 10348c2ecf20Sopenharmony_ci var->xres_virtual = 8192 * 8 / bpp; 10358c2ecf20Sopenharmony_ci else 10368c2ecf20Sopenharmony_ci return -EINVAL; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci line_length = var->xres_virtual * bpp / 8; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* datasheet specifies how to set panning only up to 4 MB */ 10428c2ecf20Sopenharmony_ci if (line_length * (var->yres_virtual - var->yres) > (4 << 20)) 10438c2ecf20Sopenharmony_ci var->yres_virtual = ((4 << 20) / line_length) + var->yres; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (line_length * var->yres_virtual > info->fix.smem_len) 10468c2ecf20Sopenharmony_ci return -EINVAL; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci switch (bpp) { 10498c2ecf20Sopenharmony_ci case 8: 10508c2ecf20Sopenharmony_ci var->red.offset = 0; 10518c2ecf20Sopenharmony_ci var->red.length = 8; 10528c2ecf20Sopenharmony_ci var->green = var->red; 10538c2ecf20Sopenharmony_ci var->blue = var->red; 10548c2ecf20Sopenharmony_ci break; 10558c2ecf20Sopenharmony_ci case 16: 10568c2ecf20Sopenharmony_ci var->red.offset = 11; 10578c2ecf20Sopenharmony_ci var->green.offset = 5; 10588c2ecf20Sopenharmony_ci var->blue.offset = 0; 10598c2ecf20Sopenharmony_ci var->red.length = 5; 10608c2ecf20Sopenharmony_ci var->green.length = 6; 10618c2ecf20Sopenharmony_ci var->blue.length = 5; 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci case 32: 10648c2ecf20Sopenharmony_ci var->red.offset = 16; 10658c2ecf20Sopenharmony_ci var->green.offset = 8; 10668c2ecf20Sopenharmony_ci var->blue.offset = 0; 10678c2ecf20Sopenharmony_ci var->red.length = 8; 10688c2ecf20Sopenharmony_ci var->green.length = 8; 10698c2ecf20Sopenharmony_ci var->blue.length = 8; 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci default: 10728c2ecf20Sopenharmony_ci return -EINVAL; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (is_xp(par->chip_id)) 10768c2ecf20Sopenharmony_ci ramdac = 350000; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci switch (par->chip_id) { 10798c2ecf20Sopenharmony_ci case TGUI9440: 10808c2ecf20Sopenharmony_ci ramdac = (bpp >= 16) ? 45000 : 90000; 10818c2ecf20Sopenharmony_ci break; 10828c2ecf20Sopenharmony_ci case CYBER9320: 10838c2ecf20Sopenharmony_ci case TGUI9660: 10848c2ecf20Sopenharmony_ci ramdac = 135000; 10858c2ecf20Sopenharmony_ci break; 10868c2ecf20Sopenharmony_ci case PROVIDIA9685: 10878c2ecf20Sopenharmony_ci case CYBER9388: 10888c2ecf20Sopenharmony_ci case CYBER9382: 10898c2ecf20Sopenharmony_ci case CYBER9385: 10908c2ecf20Sopenharmony_ci ramdac = 170000; 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* The clock is doubled for 32 bpp */ 10958c2ecf20Sopenharmony_ci if (bpp == 32) 10968c2ecf20Sopenharmony_ci ramdac /= 2; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (PICOS2KHZ(var->pixclock) > ramdac) 10998c2ecf20Sopenharmony_ci return -EINVAL; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci debug("exit\n"); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci return 0; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci/* Pan the display */ 11088c2ecf20Sopenharmony_cistatic int tridentfb_pan_display(struct fb_var_screeninfo *var, 11098c2ecf20Sopenharmony_ci struct fb_info *info) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 11128c2ecf20Sopenharmony_ci unsigned int offset; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci debug("enter\n"); 11158c2ecf20Sopenharmony_ci offset = (var->xoffset + (var->yoffset * info->var.xres_virtual)) 11168c2ecf20Sopenharmony_ci * info->var.bits_per_pixel / 32; 11178c2ecf20Sopenharmony_ci set_screen_start(par, offset); 11188c2ecf20Sopenharmony_ci debug("exit\n"); 11198c2ecf20Sopenharmony_ci return 0; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cistatic inline void shadowmode_on(struct tridentfb_par *par) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci write3CE(par, CyberControl, read3CE(par, CyberControl) | 0x81); 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic inline void shadowmode_off(struct tridentfb_par *par) 11288c2ecf20Sopenharmony_ci{ 11298c2ecf20Sopenharmony_ci write3CE(par, CyberControl, read3CE(par, CyberControl) & 0x7E); 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci/* Set the hardware to the requested video mode */ 11338c2ecf20Sopenharmony_cistatic int tridentfb_set_par(struct fb_info *info) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 11368c2ecf20Sopenharmony_ci u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend; 11378c2ecf20Sopenharmony_ci u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend; 11388c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var = &info->var; 11398c2ecf20Sopenharmony_ci int bpp = var->bits_per_pixel; 11408c2ecf20Sopenharmony_ci unsigned char tmp; 11418c2ecf20Sopenharmony_ci unsigned long vclk; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci debug("enter\n"); 11448c2ecf20Sopenharmony_ci hdispend = var->xres / 8 - 1; 11458c2ecf20Sopenharmony_ci hsyncstart = (var->xres + var->right_margin) / 8; 11468c2ecf20Sopenharmony_ci hsyncend = (var->xres + var->right_margin + var->hsync_len) / 8; 11478c2ecf20Sopenharmony_ci htotal = (var->xres + var->left_margin + var->right_margin + 11488c2ecf20Sopenharmony_ci var->hsync_len) / 8 - 5; 11498c2ecf20Sopenharmony_ci hblankstart = hdispend + 1; 11508c2ecf20Sopenharmony_ci hblankend = htotal + 3; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci vdispend = var->yres - 1; 11538c2ecf20Sopenharmony_ci vsyncstart = var->yres + var->lower_margin; 11548c2ecf20Sopenharmony_ci vsyncend = vsyncstart + var->vsync_len; 11558c2ecf20Sopenharmony_ci vtotal = var->upper_margin + vsyncend - 2; 11568c2ecf20Sopenharmony_ci vblankstart = vdispend + 1; 11578c2ecf20Sopenharmony_ci vblankend = vtotal; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (info->var.vmode & FB_VMODE_INTERLACED) { 11608c2ecf20Sopenharmony_ci vtotal /= 2; 11618c2ecf20Sopenharmony_ci vdispend /= 2; 11628c2ecf20Sopenharmony_ci vsyncstart /= 2; 11638c2ecf20Sopenharmony_ci vsyncend /= 2; 11648c2ecf20Sopenharmony_ci vblankstart /= 2; 11658c2ecf20Sopenharmony_ci vblankend /= 2; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci enable_mmio(par); 11698c2ecf20Sopenharmony_ci crtc_unlock(par); 11708c2ecf20Sopenharmony_ci write3CE(par, CyberControl, 8); 11718c2ecf20Sopenharmony_ci tmp = 0xEB; 11728c2ecf20Sopenharmony_ci if (var->sync & FB_SYNC_HOR_HIGH_ACT) 11738c2ecf20Sopenharmony_ci tmp &= ~0x40; 11748c2ecf20Sopenharmony_ci if (var->sync & FB_SYNC_VERT_HIGH_ACT) 11758c2ecf20Sopenharmony_ci tmp &= ~0x80; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (par->flatpanel && var->xres < nativex) { 11788c2ecf20Sopenharmony_ci /* 11798c2ecf20Sopenharmony_ci * on flat panels with native size larger 11808c2ecf20Sopenharmony_ci * than requested resolution decide whether 11818c2ecf20Sopenharmony_ci * we stretch or center 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_ci t_outb(par, tmp | 0xC0, VGA_MIS_W); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci shadowmode_on(par); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (center) 11888c2ecf20Sopenharmony_ci screen_center(par); 11898c2ecf20Sopenharmony_ci else if (stretch) 11908c2ecf20Sopenharmony_ci screen_stretch(par); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci } else { 11938c2ecf20Sopenharmony_ci t_outb(par, tmp, VGA_MIS_W); 11948c2ecf20Sopenharmony_ci write3CE(par, CyberControl, 8); 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* vertical timing values */ 11988c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_V_TOTAL, vtotal & 0xFF); 11998c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_V_DISP_END, vdispend & 0xFF); 12008c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_V_SYNC_START, vsyncstart & 0xFF); 12018c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_V_SYNC_END, (vsyncend & 0x0F)); 12028c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_V_BLANK_START, vblankstart & 0xFF); 12038c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_V_BLANK_END, vblankend & 0xFF); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci /* horizontal timing values */ 12068c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_H_TOTAL, htotal & 0xFF); 12078c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_H_DISP, hdispend & 0xFF); 12088c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_H_SYNC_START, hsyncstart & 0xFF); 12098c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_H_SYNC_END, 12108c2ecf20Sopenharmony_ci (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); 12118c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_H_BLANK_START, hblankstart & 0xFF); 12128c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_H_BLANK_END, hblankend & 0x1F); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci /* higher bits of vertical timing values */ 12158c2ecf20Sopenharmony_ci tmp = 0x10; 12168c2ecf20Sopenharmony_ci if (vtotal & 0x100) tmp |= 0x01; 12178c2ecf20Sopenharmony_ci if (vdispend & 0x100) tmp |= 0x02; 12188c2ecf20Sopenharmony_ci if (vsyncstart & 0x100) tmp |= 0x04; 12198c2ecf20Sopenharmony_ci if (vblankstart & 0x100) tmp |= 0x08; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (vtotal & 0x200) tmp |= 0x20; 12228c2ecf20Sopenharmony_ci if (vdispend & 0x200) tmp |= 0x40; 12238c2ecf20Sopenharmony_ci if (vsyncstart & 0x200) tmp |= 0x80; 12248c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_OVERFLOW, tmp); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci tmp = read3X4(par, CRTHiOrd) & 0x07; 12278c2ecf20Sopenharmony_ci tmp |= 0x08; /* line compare bit 10 */ 12288c2ecf20Sopenharmony_ci if (vtotal & 0x400) tmp |= 0x80; 12298c2ecf20Sopenharmony_ci if (vblankstart & 0x400) tmp |= 0x40; 12308c2ecf20Sopenharmony_ci if (vsyncstart & 0x400) tmp |= 0x20; 12318c2ecf20Sopenharmony_ci if (vdispend & 0x400) tmp |= 0x10; 12328c2ecf20Sopenharmony_ci write3X4(par, CRTHiOrd, tmp); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci tmp = (htotal >> 8) & 0x01; 12358c2ecf20Sopenharmony_ci tmp |= (hdispend >> 7) & 0x02; 12368c2ecf20Sopenharmony_ci tmp |= (hsyncstart >> 5) & 0x08; 12378c2ecf20Sopenharmony_ci tmp |= (hblankstart >> 4) & 0x10; 12388c2ecf20Sopenharmony_ci write3X4(par, HorizOverflow, tmp); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci tmp = 0x40; 12418c2ecf20Sopenharmony_ci if (vblankstart & 0x200) tmp |= 0x20; 12428c2ecf20Sopenharmony_ci//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */ 12438c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_MAX_SCAN, tmp); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_LINE_COMPARE, 0xFF); 12468c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_PRESET_ROW, 0); 12478c2ecf20Sopenharmony_ci write3X4(par, VGA_CRTC_MODE, 0xC3); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci write3X4(par, LinearAddReg, 0x20); /* enable linear addressing */ 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80; 12528c2ecf20Sopenharmony_ci /* enable access extended memory */ 12538c2ecf20Sopenharmony_ci write3X4(par, CRTCModuleTest, tmp); 12548c2ecf20Sopenharmony_ci tmp = read3CE(par, MiscIntContReg) & ~0x4; 12558c2ecf20Sopenharmony_ci if (info->var.vmode & FB_VMODE_INTERLACED) 12568c2ecf20Sopenharmony_ci tmp |= 0x4; 12578c2ecf20Sopenharmony_ci write3CE(par, MiscIntContReg, tmp); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* enable GE for text acceleration */ 12608c2ecf20Sopenharmony_ci write3X4(par, GraphEngReg, 0x80); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci switch (bpp) { 12638c2ecf20Sopenharmony_ci case 8: 12648c2ecf20Sopenharmony_ci tmp = 0x00; 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci case 16: 12678c2ecf20Sopenharmony_ci tmp = 0x05; 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci case 24: 12708c2ecf20Sopenharmony_ci tmp = 0x29; 12718c2ecf20Sopenharmony_ci break; 12728c2ecf20Sopenharmony_ci case 32: 12738c2ecf20Sopenharmony_ci tmp = 0x09; 12748c2ecf20Sopenharmony_ci break; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci write3X4(par, PixelBusReg, tmp); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci tmp = read3X4(par, DRAMControl); 12808c2ecf20Sopenharmony_ci if (!is_oldprotect(par->chip_id)) 12818c2ecf20Sopenharmony_ci tmp |= 0x10; 12828c2ecf20Sopenharmony_ci if (iscyber(par->chip_id)) 12838c2ecf20Sopenharmony_ci tmp |= 0x20; 12848c2ecf20Sopenharmony_ci write3X4(par, DRAMControl, tmp); /* both IO, linear enable */ 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci write3X4(par, InterfaceSel, read3X4(par, InterfaceSel) | 0x40); 12878c2ecf20Sopenharmony_ci if (!is_xp(par->chip_id)) 12888c2ecf20Sopenharmony_ci write3X4(par, Performance, read3X4(par, Performance) | 0x10); 12898c2ecf20Sopenharmony_ci /* MMIO & PCI read and write burst enable */ 12908c2ecf20Sopenharmony_ci if (par->chip_id != TGUI9440 && par->chip_id != IMAGE975) 12918c2ecf20Sopenharmony_ci write3X4(par, PCIReg, read3X4(par, PCIReg) | 0x06); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, 0, 3); 12948c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, 1, 1); /* set char clock 8 dots wide */ 12958c2ecf20Sopenharmony_ci /* enable 4 maps because needed in chain4 mode */ 12968c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, 2, 0x0F); 12978c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, 3, 0); 12988c2ecf20Sopenharmony_ci vga_mm_wseq(par->io_virt, 4, 0x0E); /* memory mode enable bitmaps ?? */ 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* convert from picoseconds to kHz */ 13018c2ecf20Sopenharmony_ci vclk = PICOS2KHZ(info->var.pixclock); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* divide clock by 2 if 32bpp chain4 mode display and CPU path */ 13048c2ecf20Sopenharmony_ci tmp = read3CE(par, MiscExtFunc) & 0xF0; 13058c2ecf20Sopenharmony_ci if (bpp == 32 || (par->chip_id == TGUI9440 && bpp == 16)) { 13068c2ecf20Sopenharmony_ci tmp |= 8; 13078c2ecf20Sopenharmony_ci vclk *= 2; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci set_vclk(par, vclk); 13108c2ecf20Sopenharmony_ci write3CE(par, MiscExtFunc, tmp | 0x12); 13118c2ecf20Sopenharmony_ci write3CE(par, 0x5, 0x40); /* no CGA compat, allow 256 col */ 13128c2ecf20Sopenharmony_ci write3CE(par, 0x6, 0x05); /* graphics mode */ 13138c2ecf20Sopenharmony_ci write3CE(par, 0x7, 0x0F); /* planes? */ 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* graphics mode and support 256 color modes */ 13168c2ecf20Sopenharmony_ci writeAttr(par, 0x10, 0x41); 13178c2ecf20Sopenharmony_ci writeAttr(par, 0x12, 0x0F); /* planes */ 13188c2ecf20Sopenharmony_ci writeAttr(par, 0x13, 0); /* horizontal pel panning */ 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* colors */ 13218c2ecf20Sopenharmony_ci for (tmp = 0; tmp < 0x10; tmp++) 13228c2ecf20Sopenharmony_ci writeAttr(par, tmp, tmp); 13238c2ecf20Sopenharmony_ci fb_readb(par->io_virt + VGA_IS1_RC); /* flip-flop to index */ 13248c2ecf20Sopenharmony_ci t_outb(par, 0x20, VGA_ATT_W); /* enable attr */ 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci switch (bpp) { 13278c2ecf20Sopenharmony_ci case 8: 13288c2ecf20Sopenharmony_ci tmp = 0; 13298c2ecf20Sopenharmony_ci break; 13308c2ecf20Sopenharmony_ci case 16: 13318c2ecf20Sopenharmony_ci tmp = 0x30; 13328c2ecf20Sopenharmony_ci break; 13338c2ecf20Sopenharmony_ci case 24: 13348c2ecf20Sopenharmony_ci case 32: 13358c2ecf20Sopenharmony_ci tmp = 0xD0; 13368c2ecf20Sopenharmony_ci break; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci t_inb(par, VGA_PEL_IW); 13408c2ecf20Sopenharmony_ci t_inb(par, VGA_PEL_MSK); 13418c2ecf20Sopenharmony_ci t_inb(par, VGA_PEL_MSK); 13428c2ecf20Sopenharmony_ci t_inb(par, VGA_PEL_MSK); 13438c2ecf20Sopenharmony_ci t_inb(par, VGA_PEL_MSK); 13448c2ecf20Sopenharmony_ci t_outb(par, tmp, VGA_PEL_MSK); 13458c2ecf20Sopenharmony_ci t_inb(par, VGA_PEL_IW); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (par->flatpanel) 13488c2ecf20Sopenharmony_ci set_number_of_lines(par, info->var.yres); 13498c2ecf20Sopenharmony_ci info->fix.line_length = info->var.xres_virtual * bpp / 8; 13508c2ecf20Sopenharmony_ci set_lwidth(par, info->fix.line_length / 8); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (!(info->flags & FBINFO_HWACCEL_DISABLED)) 13538c2ecf20Sopenharmony_ci par->init_accel(par, info->var.xres_virtual, bpp); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 13568c2ecf20Sopenharmony_ci info->cmap.len = (bpp == 8) ? 256 : 16; 13578c2ecf20Sopenharmony_ci debug("exit\n"); 13588c2ecf20Sopenharmony_ci return 0; 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci/* Set one color register */ 13628c2ecf20Sopenharmony_cistatic int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green, 13638c2ecf20Sopenharmony_ci unsigned blue, unsigned transp, 13648c2ecf20Sopenharmony_ci struct fb_info *info) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci int bpp = info->var.bits_per_pixel; 13678c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (regno >= info->cmap.len) 13708c2ecf20Sopenharmony_ci return 1; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (bpp == 8) { 13738c2ecf20Sopenharmony_ci t_outb(par, 0xFF, VGA_PEL_MSK); 13748c2ecf20Sopenharmony_ci t_outb(par, regno, VGA_PEL_IW); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci t_outb(par, red >> 10, VGA_PEL_D); 13778c2ecf20Sopenharmony_ci t_outb(par, green >> 10, VGA_PEL_D); 13788c2ecf20Sopenharmony_ci t_outb(par, blue >> 10, VGA_PEL_D); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci } else if (regno < 16) { 13818c2ecf20Sopenharmony_ci if (bpp == 16) { /* RGB 565 */ 13828c2ecf20Sopenharmony_ci u32 col; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci col = (red & 0xF800) | ((green & 0xFC00) >> 5) | 13858c2ecf20Sopenharmony_ci ((blue & 0xF800) >> 11); 13868c2ecf20Sopenharmony_ci col |= col << 16; 13878c2ecf20Sopenharmony_ci ((u32 *)(info->pseudo_palette))[regno] = col; 13888c2ecf20Sopenharmony_ci } else if (bpp == 32) /* ARGB 8888 */ 13898c2ecf20Sopenharmony_ci ((u32 *)info->pseudo_palette)[regno] = 13908c2ecf20Sopenharmony_ci ((transp & 0xFF00) << 16) | 13918c2ecf20Sopenharmony_ci ((red & 0xFF00) << 8) | 13928c2ecf20Sopenharmony_ci ((green & 0xFF00)) | 13938c2ecf20Sopenharmony_ci ((blue & 0xFF00) >> 8); 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci return 0; 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci/* Try blanking the screen. For flat panels it does nothing */ 14008c2ecf20Sopenharmony_cistatic int tridentfb_blank(int blank_mode, struct fb_info *info) 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci unsigned char PMCont, DPMSCont; 14038c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci debug("enter\n"); 14068c2ecf20Sopenharmony_ci if (par->flatpanel) 14078c2ecf20Sopenharmony_ci return 0; 14088c2ecf20Sopenharmony_ci t_outb(par, 0x04, 0x83C8); /* Read DPMS Control */ 14098c2ecf20Sopenharmony_ci PMCont = t_inb(par, 0x83C6) & 0xFC; 14108c2ecf20Sopenharmony_ci DPMSCont = read3CE(par, PowerStatus) & 0xFC; 14118c2ecf20Sopenharmony_ci switch (blank_mode) { 14128c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 14138c2ecf20Sopenharmony_ci /* Screen: On, HSync: On, VSync: On */ 14148c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: 14158c2ecf20Sopenharmony_ci /* Screen: Off, HSync: On, VSync: On */ 14168c2ecf20Sopenharmony_ci PMCont |= 0x03; 14178c2ecf20Sopenharmony_ci DPMSCont |= 0x00; 14188c2ecf20Sopenharmony_ci break; 14198c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 14208c2ecf20Sopenharmony_ci /* Screen: Off, HSync: Off, VSync: On */ 14218c2ecf20Sopenharmony_ci PMCont |= 0x02; 14228c2ecf20Sopenharmony_ci DPMSCont |= 0x01; 14238c2ecf20Sopenharmony_ci break; 14248c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 14258c2ecf20Sopenharmony_ci /* Screen: Off, HSync: On, VSync: Off */ 14268c2ecf20Sopenharmony_ci PMCont |= 0x02; 14278c2ecf20Sopenharmony_ci DPMSCont |= 0x02; 14288c2ecf20Sopenharmony_ci break; 14298c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 14308c2ecf20Sopenharmony_ci /* Screen: Off, HSync: Off, VSync: Off */ 14318c2ecf20Sopenharmony_ci PMCont |= 0x00; 14328c2ecf20Sopenharmony_ci DPMSCont |= 0x03; 14338c2ecf20Sopenharmony_ci break; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci write3CE(par, PowerStatus, DPMSCont); 14378c2ecf20Sopenharmony_ci t_outb(par, 4, 0x83C8); 14388c2ecf20Sopenharmony_ci t_outb(par, PMCont, 0x83C6); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci debug("exit\n"); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci /* let fbcon do a softblank for us */ 14438c2ecf20Sopenharmony_ci return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic const struct fb_ops tridentfb_ops = { 14478c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 14488c2ecf20Sopenharmony_ci .fb_setcolreg = tridentfb_setcolreg, 14498c2ecf20Sopenharmony_ci .fb_pan_display = tridentfb_pan_display, 14508c2ecf20Sopenharmony_ci .fb_blank = tridentfb_blank, 14518c2ecf20Sopenharmony_ci .fb_check_var = tridentfb_check_var, 14528c2ecf20Sopenharmony_ci .fb_set_par = tridentfb_set_par, 14538c2ecf20Sopenharmony_ci .fb_fillrect = tridentfb_fillrect, 14548c2ecf20Sopenharmony_ci .fb_copyarea = tridentfb_copyarea, 14558c2ecf20Sopenharmony_ci .fb_imageblit = tridentfb_imageblit, 14568c2ecf20Sopenharmony_ci .fb_sync = tridentfb_sync, 14578c2ecf20Sopenharmony_ci}; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_cistatic int trident_pci_probe(struct pci_dev *dev, 14608c2ecf20Sopenharmony_ci const struct pci_device_id *id) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci int err; 14638c2ecf20Sopenharmony_ci unsigned char revision; 14648c2ecf20Sopenharmony_ci struct fb_info *info; 14658c2ecf20Sopenharmony_ci struct tridentfb_par *default_par; 14668c2ecf20Sopenharmony_ci int chip3D; 14678c2ecf20Sopenharmony_ci int chip_id; 14688c2ecf20Sopenharmony_ci bool found = false; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci err = pci_enable_device(dev); 14718c2ecf20Sopenharmony_ci if (err) 14728c2ecf20Sopenharmony_ci return err; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct tridentfb_par), &dev->dev); 14758c2ecf20Sopenharmony_ci if (!info) 14768c2ecf20Sopenharmony_ci return -ENOMEM; 14778c2ecf20Sopenharmony_ci default_par = info->par; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci chip_id = id->device; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci /* If PCI id is 0x9660 then further detect chip type */ 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (chip_id == TGUI9660) { 14848c2ecf20Sopenharmony_ci revision = vga_io_rseq(RevisionID); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci switch (revision) { 14878c2ecf20Sopenharmony_ci case 0x21: 14888c2ecf20Sopenharmony_ci chip_id = PROVIDIA9685; 14898c2ecf20Sopenharmony_ci break; 14908c2ecf20Sopenharmony_ci case 0x22: 14918c2ecf20Sopenharmony_ci case 0x23: 14928c2ecf20Sopenharmony_ci chip_id = CYBER9397; 14938c2ecf20Sopenharmony_ci break; 14948c2ecf20Sopenharmony_ci case 0x2A: 14958c2ecf20Sopenharmony_ci chip_id = CYBER9397DVD; 14968c2ecf20Sopenharmony_ci break; 14978c2ecf20Sopenharmony_ci case 0x30: 14988c2ecf20Sopenharmony_ci case 0x33: 14998c2ecf20Sopenharmony_ci case 0x34: 15008c2ecf20Sopenharmony_ci case 0x35: 15018c2ecf20Sopenharmony_ci case 0x38: 15028c2ecf20Sopenharmony_ci case 0x3A: 15038c2ecf20Sopenharmony_ci case 0xB3: 15048c2ecf20Sopenharmony_ci chip_id = CYBER9385; 15058c2ecf20Sopenharmony_ci break; 15068c2ecf20Sopenharmony_ci case 0x40 ... 0x43: 15078c2ecf20Sopenharmony_ci chip_id = CYBER9382; 15088c2ecf20Sopenharmony_ci break; 15098c2ecf20Sopenharmony_ci case 0x4A: 15108c2ecf20Sopenharmony_ci chip_id = CYBER9388; 15118c2ecf20Sopenharmony_ci break; 15128c2ecf20Sopenharmony_ci default: 15138c2ecf20Sopenharmony_ci break; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci chip3D = is3Dchip(chip_id); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (is_xp(chip_id)) { 15208c2ecf20Sopenharmony_ci default_par->init_accel = xp_init_accel; 15218c2ecf20Sopenharmony_ci default_par->wait_engine = xp_wait_engine; 15228c2ecf20Sopenharmony_ci default_par->fill_rect = xp_fill_rect; 15238c2ecf20Sopenharmony_ci default_par->copy_rect = xp_copy_rect; 15248c2ecf20Sopenharmony_ci tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADEXP; 15258c2ecf20Sopenharmony_ci } else if (is_blade(chip_id)) { 15268c2ecf20Sopenharmony_ci default_par->init_accel = blade_init_accel; 15278c2ecf20Sopenharmony_ci default_par->wait_engine = blade_wait_engine; 15288c2ecf20Sopenharmony_ci default_par->fill_rect = blade_fill_rect; 15298c2ecf20Sopenharmony_ci default_par->copy_rect = blade_copy_rect; 15308c2ecf20Sopenharmony_ci default_par->image_blit = blade_image_blit; 15318c2ecf20Sopenharmony_ci tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADE3D; 15328c2ecf20Sopenharmony_ci } else if (chip3D) { /* 3DImage family left */ 15338c2ecf20Sopenharmony_ci default_par->init_accel = image_init_accel; 15348c2ecf20Sopenharmony_ci default_par->wait_engine = image_wait_engine; 15358c2ecf20Sopenharmony_ci default_par->fill_rect = image_fill_rect; 15368c2ecf20Sopenharmony_ci default_par->copy_rect = image_copy_rect; 15378c2ecf20Sopenharmony_ci tridentfb_fix.accel = FB_ACCEL_TRIDENT_3DIMAGE; 15388c2ecf20Sopenharmony_ci } else { /* TGUI 9440/96XX family */ 15398c2ecf20Sopenharmony_ci default_par->init_accel = tgui_init_accel; 15408c2ecf20Sopenharmony_ci default_par->wait_engine = xp_wait_engine; 15418c2ecf20Sopenharmony_ci default_par->fill_rect = tgui_fill_rect; 15428c2ecf20Sopenharmony_ci default_par->copy_rect = tgui_copy_rect; 15438c2ecf20Sopenharmony_ci tridentfb_fix.accel = FB_ACCEL_TRIDENT_TGUI; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci default_par->chip_id = chip_id; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* setup MMIO region */ 15498c2ecf20Sopenharmony_ci tridentfb_fix.mmio_start = pci_resource_start(dev, 1); 15508c2ecf20Sopenharmony_ci tridentfb_fix.mmio_len = pci_resource_len(dev, 1); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (!request_mem_region(tridentfb_fix.mmio_start, 15538c2ecf20Sopenharmony_ci tridentfb_fix.mmio_len, "tridentfb")) { 15548c2ecf20Sopenharmony_ci debug("request_region failed!\n"); 15558c2ecf20Sopenharmony_ci framebuffer_release(info); 15568c2ecf20Sopenharmony_ci return -1; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci default_par->io_virt = ioremap(tridentfb_fix.mmio_start, 15608c2ecf20Sopenharmony_ci tridentfb_fix.mmio_len); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci if (!default_par->io_virt) { 15638c2ecf20Sopenharmony_ci debug("ioremap failed\n"); 15648c2ecf20Sopenharmony_ci err = -1; 15658c2ecf20Sopenharmony_ci goto out_unmap1; 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci enable_mmio(default_par); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci /* setup framebuffer memory */ 15718c2ecf20Sopenharmony_ci tridentfb_fix.smem_start = pci_resource_start(dev, 0); 15728c2ecf20Sopenharmony_ci tridentfb_fix.smem_len = get_memsize(default_par); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci if (!request_mem_region(tridentfb_fix.smem_start, 15758c2ecf20Sopenharmony_ci tridentfb_fix.smem_len, "tridentfb")) { 15768c2ecf20Sopenharmony_ci debug("request_mem_region failed!\n"); 15778c2ecf20Sopenharmony_ci disable_mmio(info->par); 15788c2ecf20Sopenharmony_ci err = -1; 15798c2ecf20Sopenharmony_ci goto out_unmap1; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci info->screen_base = ioremap(tridentfb_fix.smem_start, 15838c2ecf20Sopenharmony_ci tridentfb_fix.smem_len); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci if (!info->screen_base) { 15868c2ecf20Sopenharmony_ci debug("ioremap failed\n"); 15878c2ecf20Sopenharmony_ci err = -1; 15888c2ecf20Sopenharmony_ci goto out_unmap2; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci default_par->flatpanel = is_flatpanel(default_par); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (default_par->flatpanel) 15948c2ecf20Sopenharmony_ci nativex = get_nativex(default_par); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci info->fix = tridentfb_fix; 15978c2ecf20Sopenharmony_ci info->fbops = &tridentfb_ops; 15988c2ecf20Sopenharmony_ci info->pseudo_palette = default_par->pseudo_pal; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; 16018c2ecf20Sopenharmony_ci if (!noaccel && default_par->init_accel) { 16028c2ecf20Sopenharmony_ci info->flags &= ~FBINFO_HWACCEL_DISABLED; 16038c2ecf20Sopenharmony_ci info->flags |= FBINFO_HWACCEL_COPYAREA; 16048c2ecf20Sopenharmony_ci info->flags |= FBINFO_HWACCEL_FILLRECT; 16058c2ecf20Sopenharmony_ci } else 16068c2ecf20Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (is_blade(chip_id) && chip_id != BLADE3D) 16098c2ecf20Sopenharmony_ci info->flags |= FBINFO_READS_FAST; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci info->pixmap.addr = kmalloc(4096, GFP_KERNEL); 16128c2ecf20Sopenharmony_ci if (!info->pixmap.addr) { 16138c2ecf20Sopenharmony_ci err = -ENOMEM; 16148c2ecf20Sopenharmony_ci goto out_unmap2; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci info->pixmap.size = 4096; 16188c2ecf20Sopenharmony_ci info->pixmap.buf_align = 4; 16198c2ecf20Sopenharmony_ci info->pixmap.scan_align = 1; 16208c2ecf20Sopenharmony_ci info->pixmap.access_align = 32; 16218c2ecf20Sopenharmony_ci info->pixmap.flags = FB_PIXMAP_SYSTEM; 16228c2ecf20Sopenharmony_ci info->var.bits_per_pixel = 8; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci if (default_par->image_blit) { 16258c2ecf20Sopenharmony_ci info->flags |= FBINFO_HWACCEL_IMAGEBLIT; 16268c2ecf20Sopenharmony_ci info->pixmap.scan_align = 4; 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci if (noaccel) { 16308c2ecf20Sopenharmony_ci printk(KERN_DEBUG "disabling acceleration\n"); 16318c2ecf20Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 16328c2ecf20Sopenharmony_ci info->pixmap.scan_align = 1; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (tridentfb_setup_ddc_bus(info) == 0) { 16368c2ecf20Sopenharmony_ci u8 *edid = fb_ddc_read(&default_par->ddc_adapter); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci default_par->ddc_registered = true; 16398c2ecf20Sopenharmony_ci if (edid) { 16408c2ecf20Sopenharmony_ci fb_edid_to_monspecs(edid, &info->monspecs); 16418c2ecf20Sopenharmony_ci kfree(edid); 16428c2ecf20Sopenharmony_ci if (!info->monspecs.modedb) 16438c2ecf20Sopenharmony_ci dev_err(info->device, "error getting mode database\n"); 16448c2ecf20Sopenharmony_ci else { 16458c2ecf20Sopenharmony_ci const struct fb_videomode *m; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci fb_videomode_to_modelist(info->monspecs.modedb, 16488c2ecf20Sopenharmony_ci info->monspecs.modedb_len, 16498c2ecf20Sopenharmony_ci &info->modelist); 16508c2ecf20Sopenharmony_ci m = fb_find_best_display(&info->monspecs, 16518c2ecf20Sopenharmony_ci &info->modelist); 16528c2ecf20Sopenharmony_ci if (m) { 16538c2ecf20Sopenharmony_ci fb_videomode_to_var(&info->var, m); 16548c2ecf20Sopenharmony_ci /* fill all other info->var's fields */ 16558c2ecf20Sopenharmony_ci if (tridentfb_check_var(&info->var, 16568c2ecf20Sopenharmony_ci info) == 0) 16578c2ecf20Sopenharmony_ci found = true; 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci if (!mode_option && !found) 16648c2ecf20Sopenharmony_ci mode_option = "640x480-8@60"; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci /* Prepare startup mode */ 16678c2ecf20Sopenharmony_ci if (mode_option) { 16688c2ecf20Sopenharmony_ci err = fb_find_mode(&info->var, info, mode_option, 16698c2ecf20Sopenharmony_ci info->monspecs.modedb, 16708c2ecf20Sopenharmony_ci info->monspecs.modedb_len, 16718c2ecf20Sopenharmony_ci NULL, info->var.bits_per_pixel); 16728c2ecf20Sopenharmony_ci if (!err || err == 4) { 16738c2ecf20Sopenharmony_ci err = -EINVAL; 16748c2ecf20Sopenharmony_ci dev_err(info->device, "mode %s not found\n", 16758c2ecf20Sopenharmony_ci mode_option); 16768c2ecf20Sopenharmony_ci fb_destroy_modedb(info->monspecs.modedb); 16778c2ecf20Sopenharmony_ci info->monspecs.modedb = NULL; 16788c2ecf20Sopenharmony_ci goto out_unmap2; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci fb_destroy_modedb(info->monspecs.modedb); 16838c2ecf20Sopenharmony_ci info->monspecs.modedb = NULL; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci err = fb_alloc_cmap(&info->cmap, 256, 0); 16868c2ecf20Sopenharmony_ci if (err < 0) 16878c2ecf20Sopenharmony_ci goto out_unmap2; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci info->var.activate |= FB_ACTIVATE_NOW; 16908c2ecf20Sopenharmony_ci info->device = &dev->dev; 16918c2ecf20Sopenharmony_ci if (register_framebuffer(info) < 0) { 16928c2ecf20Sopenharmony_ci printk(KERN_ERR "tridentfb: could not register framebuffer\n"); 16938c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 16948c2ecf20Sopenharmony_ci err = -EINVAL; 16958c2ecf20Sopenharmony_ci goto out_unmap2; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci output("fb%d: %s frame buffer device %dx%d-%dbpp\n", 16988c2ecf20Sopenharmony_ci info->node, info->fix.id, info->var.xres, 16998c2ecf20Sopenharmony_ci info->var.yres, info->var.bits_per_pixel); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci pci_set_drvdata(dev, info); 17028c2ecf20Sopenharmony_ci return 0; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ciout_unmap2: 17058c2ecf20Sopenharmony_ci if (default_par->ddc_registered) 17068c2ecf20Sopenharmony_ci i2c_del_adapter(&default_par->ddc_adapter); 17078c2ecf20Sopenharmony_ci kfree(info->pixmap.addr); 17088c2ecf20Sopenharmony_ci if (info->screen_base) 17098c2ecf20Sopenharmony_ci iounmap(info->screen_base); 17108c2ecf20Sopenharmony_ci release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); 17118c2ecf20Sopenharmony_ci disable_mmio(info->par); 17128c2ecf20Sopenharmony_ciout_unmap1: 17138c2ecf20Sopenharmony_ci if (default_par->io_virt) 17148c2ecf20Sopenharmony_ci iounmap(default_par->io_virt); 17158c2ecf20Sopenharmony_ci release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); 17168c2ecf20Sopenharmony_ci framebuffer_release(info); 17178c2ecf20Sopenharmony_ci return err; 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_cistatic void trident_pci_remove(struct pci_dev *dev) 17218c2ecf20Sopenharmony_ci{ 17228c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(dev); 17238c2ecf20Sopenharmony_ci struct tridentfb_par *par = info->par; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci unregister_framebuffer(info); 17268c2ecf20Sopenharmony_ci if (par->ddc_registered) 17278c2ecf20Sopenharmony_ci i2c_del_adapter(&par->ddc_adapter); 17288c2ecf20Sopenharmony_ci iounmap(par->io_virt); 17298c2ecf20Sopenharmony_ci iounmap(info->screen_base); 17308c2ecf20Sopenharmony_ci release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len); 17318c2ecf20Sopenharmony_ci release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len); 17328c2ecf20Sopenharmony_ci kfree(info->pixmap.addr); 17338c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 17348c2ecf20Sopenharmony_ci framebuffer_release(info); 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci/* List of boards that we are trying to support */ 17388c2ecf20Sopenharmony_cistatic const struct pci_device_id trident_devices[] = { 17398c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17408c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17418c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17428c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17438c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17448c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17458c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17468c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17478c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, TGUI9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17488c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17498c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17508c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17518c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17528c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17538c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17548c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17558c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17568c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17578c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17588c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17598c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 17608c2ecf20Sopenharmony_ci {0,} 17618c2ecf20Sopenharmony_ci}; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, trident_devices); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_cistatic struct pci_driver tridentfb_pci_driver = { 17668c2ecf20Sopenharmony_ci .name = "tridentfb", 17678c2ecf20Sopenharmony_ci .id_table = trident_devices, 17688c2ecf20Sopenharmony_ci .probe = trident_pci_probe, 17698c2ecf20Sopenharmony_ci .remove = trident_pci_remove, 17708c2ecf20Sopenharmony_ci}; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci/* 17738c2ecf20Sopenharmony_ci * Parse user specified options (`video=trident:') 17748c2ecf20Sopenharmony_ci * example: 17758c2ecf20Sopenharmony_ci * video=trident:800x600,bpp=16,noaccel 17768c2ecf20Sopenharmony_ci */ 17778c2ecf20Sopenharmony_ci#ifndef MODULE 17788c2ecf20Sopenharmony_cistatic int __init tridentfb_setup(char *options) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci char *opt; 17818c2ecf20Sopenharmony_ci if (!options || !*options) 17828c2ecf20Sopenharmony_ci return 0; 17838c2ecf20Sopenharmony_ci while ((opt = strsep(&options, ",")) != NULL) { 17848c2ecf20Sopenharmony_ci if (!*opt) 17858c2ecf20Sopenharmony_ci continue; 17868c2ecf20Sopenharmony_ci if (!strncmp(opt, "noaccel", 7)) 17878c2ecf20Sopenharmony_ci noaccel = 1; 17888c2ecf20Sopenharmony_ci else if (!strncmp(opt, "fp", 2)) 17898c2ecf20Sopenharmony_ci fp = 1; 17908c2ecf20Sopenharmony_ci else if (!strncmp(opt, "crt", 3)) 17918c2ecf20Sopenharmony_ci fp = 0; 17928c2ecf20Sopenharmony_ci else if (!strncmp(opt, "bpp=", 4)) 17938c2ecf20Sopenharmony_ci bpp = simple_strtoul(opt + 4, NULL, 0); 17948c2ecf20Sopenharmony_ci else if (!strncmp(opt, "center", 6)) 17958c2ecf20Sopenharmony_ci center = 1; 17968c2ecf20Sopenharmony_ci else if (!strncmp(opt, "stretch", 7)) 17978c2ecf20Sopenharmony_ci stretch = 1; 17988c2ecf20Sopenharmony_ci else if (!strncmp(opt, "memsize=", 8)) 17998c2ecf20Sopenharmony_ci memsize = simple_strtoul(opt + 8, NULL, 0); 18008c2ecf20Sopenharmony_ci else if (!strncmp(opt, "memdiff=", 8)) 18018c2ecf20Sopenharmony_ci memdiff = simple_strtoul(opt + 8, NULL, 0); 18028c2ecf20Sopenharmony_ci else if (!strncmp(opt, "nativex=", 8)) 18038c2ecf20Sopenharmony_ci nativex = simple_strtoul(opt + 8, NULL, 0); 18048c2ecf20Sopenharmony_ci else 18058c2ecf20Sopenharmony_ci mode_option = opt; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci return 0; 18088c2ecf20Sopenharmony_ci} 18098c2ecf20Sopenharmony_ci#endif 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic int __init tridentfb_init(void) 18128c2ecf20Sopenharmony_ci{ 18138c2ecf20Sopenharmony_ci#ifndef MODULE 18148c2ecf20Sopenharmony_ci char *option = NULL; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (fb_get_options("tridentfb", &option)) 18178c2ecf20Sopenharmony_ci return -ENODEV; 18188c2ecf20Sopenharmony_ci tridentfb_setup(option); 18198c2ecf20Sopenharmony_ci#endif 18208c2ecf20Sopenharmony_ci return pci_register_driver(&tridentfb_pci_driver); 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic void __exit tridentfb_exit(void) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci pci_unregister_driver(&tridentfb_pci_driver); 18268c2ecf20Sopenharmony_ci} 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_cimodule_init(tridentfb_init); 18298c2ecf20Sopenharmony_cimodule_exit(tridentfb_exit); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jani Monoses <jani@iv.ro>"); 18328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Framebuffer driver for Trident cards"); 18338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 18348c2ecf20Sopenharmony_ciMODULE_ALIAS("cyblafb"); 18358c2ecf20Sopenharmony_ci 1836