18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl> 78c2ecf20Sopenharmony_ci * based on pm2fb.c 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on code written by: 108c2ecf20Sopenharmony_ci * Sven Luther, <luther@dpt-info.u-strasbg.fr> 118c2ecf20Sopenharmony_ci * Alan Hourihane, <alanh@fairlite.demon.co.uk> 128c2ecf20Sopenharmony_ci * Russell King, <rmk@arm.linux.org.uk> 138c2ecf20Sopenharmony_ci * Based on linux/drivers/video/skeletonfb.c: 148c2ecf20Sopenharmony_ci * Copyright (C) 1997 Geert Uytterhoeven 158c2ecf20Sopenharmony_ci * Based on linux/driver/video/pm2fb.c: 168c2ecf20Sopenharmony_ci * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) 178c2ecf20Sopenharmony_ci * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 208c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 218c2ecf20Sopenharmony_ci * more details. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/kernel.h> 278c2ecf20Sopenharmony_ci#include <linux/errno.h> 288c2ecf20Sopenharmony_ci#include <linux/string.h> 298c2ecf20Sopenharmony_ci#include <linux/mm.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/delay.h> 328c2ecf20Sopenharmony_ci#include <linux/fb.h> 338c2ecf20Sopenharmony_ci#include <linux/init.h> 348c2ecf20Sopenharmony_ci#include <linux/pci.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <video/pm3fb.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#if !defined(CONFIG_PCI) 398c2ecf20Sopenharmony_ci#error "Only generic PCI cards supported." 408c2ecf20Sopenharmony_ci#endif 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#undef PM3FB_MASTER_DEBUG 438c2ecf20Sopenharmony_ci#ifdef PM3FB_MASTER_DEBUG 448c2ecf20Sopenharmony_ci#define DPRINTK(a, b...) \ 458c2ecf20Sopenharmony_ci printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b) 468c2ecf20Sopenharmony_ci#else 478c2ecf20Sopenharmony_ci#define DPRINTK(a, b...) no_printk(a, ##b) 488c2ecf20Sopenharmony_ci#endif 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define PM3_PIXMAP_SIZE (2048 * 4) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * Driver data 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic int hwcursor = 1; 568c2ecf20Sopenharmony_cistatic char *mode_option; 578c2ecf20Sopenharmony_cistatic bool noaccel; 588c2ecf20Sopenharmony_cistatic bool nomtrr; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * This structure defines the hardware state of the graphics card. Normally 628c2ecf20Sopenharmony_ci * you place this in a header file in linux/include/video. This file usually 638c2ecf20Sopenharmony_ci * also includes register information. That allows other driver subsystems 648c2ecf20Sopenharmony_ci * and userland applications the ability to use the same header file to 658c2ecf20Sopenharmony_ci * avoid duplicate work and easy porting of software. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistruct pm3_par { 688c2ecf20Sopenharmony_ci unsigned char __iomem *v_regs;/* virtual address of p_regs */ 698c2ecf20Sopenharmony_ci u32 video; /* video flags before blanking */ 708c2ecf20Sopenharmony_ci u32 base; /* screen base in 128 bits unit */ 718c2ecf20Sopenharmony_ci u32 palette[16]; 728c2ecf20Sopenharmony_ci int wc_cookie; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo 778c2ecf20Sopenharmony_ci * if we don't use modedb. If we do use modedb see pm3fb_init how to use it 788c2ecf20Sopenharmony_ci * to get a fb_var_screeninfo. Otherwise define a default var as well. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic struct fb_fix_screeninfo pm3fb_fix = { 818c2ecf20Sopenharmony_ci .id = "Permedia3", 828c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 838c2ecf20Sopenharmony_ci .visual = FB_VISUAL_PSEUDOCOLOR, 848c2ecf20Sopenharmony_ci .xpanstep = 1, 858c2ecf20Sopenharmony_ci .ypanstep = 1, 868c2ecf20Sopenharmony_ci .ywrapstep = 0, 878c2ecf20Sopenharmony_ci .accel = FB_ACCEL_3DLABS_PERMEDIA3, 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * Utility functions 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic inline u32 PM3_READ_REG(struct pm3_par *par, s32 off) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return fb_readl(par->v_regs + off); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci fb_writel(v, par->v_regs + off); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic inline void PM3_WAIT(struct pm3_par *par, u32 n) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci while (PM3_READ_REG(par, PM3InFIFOSpace) < n) 1078c2ecf20Sopenharmony_ci cpu_relax(); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci PM3_WAIT(par, 3); 1138c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff); 1148c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff); 1158c2ecf20Sopenharmony_ci wmb(); 1168c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_IndexedData, v); 1178c2ecf20Sopenharmony_ci wmb(); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno, 1218c2ecf20Sopenharmony_ci unsigned char r, unsigned char g, unsigned char b) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci PM3_WAIT(par, 4); 1248c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno); 1258c2ecf20Sopenharmony_ci wmb(); 1268c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_PaletteData, r); 1278c2ecf20Sopenharmony_ci wmb(); 1288c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_PaletteData, g); 1298c2ecf20Sopenharmony_ci wmb(); 1308c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_PaletteData, b); 1318c2ecf20Sopenharmony_ci wmb(); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void pm3fb_clear_colormap(struct pm3_par *par, 1358c2ecf20Sopenharmony_ci unsigned char r, unsigned char g, unsigned char b) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int i; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for (i = 0; i < 256 ; i++) 1408c2ecf20Sopenharmony_ci pm3fb_set_color(par, i, r, g, b); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* Calculating various clock parameters */ 1458c2ecf20Sopenharmony_cistatic void pm3fb_calculate_clock(unsigned long reqclock, 1468c2ecf20Sopenharmony_ci unsigned char *prescale, 1478c2ecf20Sopenharmony_ci unsigned char *feedback, 1488c2ecf20Sopenharmony_ci unsigned char *postscale) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int f, pre, post; 1518c2ecf20Sopenharmony_ci unsigned long freq; 1528c2ecf20Sopenharmony_ci long freqerr = 1000; 1538c2ecf20Sopenharmony_ci long currerr; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci for (f = 1; f < 256; f++) { 1568c2ecf20Sopenharmony_ci for (pre = 1; pre < 256; pre++) { 1578c2ecf20Sopenharmony_ci for (post = 0; post < 5; post++) { 1588c2ecf20Sopenharmony_ci freq = ((2*PM3_REF_CLOCK * f) >> post) / pre; 1598c2ecf20Sopenharmony_ci currerr = (reqclock > freq) 1608c2ecf20Sopenharmony_ci ? reqclock - freq 1618c2ecf20Sopenharmony_ci : freq - reqclock; 1628c2ecf20Sopenharmony_ci if (currerr < freqerr) { 1638c2ecf20Sopenharmony_ci freqerr = currerr; 1648c2ecf20Sopenharmony_ci *feedback = f; 1658c2ecf20Sopenharmony_ci *prescale = pre; 1668c2ecf20Sopenharmony_ci *postscale = post; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic inline int pm3fb_depth(const struct fb_var_screeninfo *var) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci if (var->bits_per_pixel == 16) 1768c2ecf20Sopenharmony_ci return var->red.length + var->green.length 1778c2ecf20Sopenharmony_ci + var->blue.length; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return var->bits_per_pixel; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic inline int pm3fb_shift_bpp(unsigned bpp, int v) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci switch (bpp) { 1858c2ecf20Sopenharmony_ci case 8: 1868c2ecf20Sopenharmony_ci return (v >> 4); 1878c2ecf20Sopenharmony_ci case 16: 1888c2ecf20Sopenharmony_ci return (v >> 3); 1898c2ecf20Sopenharmony_ci case 32: 1908c2ecf20Sopenharmony_ci return (v >> 2); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci DPRINTK("Unsupported depth %u\n", bpp); 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* acceleration */ 1978c2ecf20Sopenharmony_cistatic int pm3fb_sync(struct fb_info *info) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci PM3_WAIT(par, 2); 2028c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); 2038c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Sync, 0); 2048c2ecf20Sopenharmony_ci mb(); 2058c2ecf20Sopenharmony_ci do { 2068c2ecf20Sopenharmony_ci while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0) 2078c2ecf20Sopenharmony_ci cpu_relax(); 2088c2ecf20Sopenharmony_ci } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic void pm3fb_init_engine(struct fb_info *info) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 2168c2ecf20Sopenharmony_ci const u32 width = (info->var.xres_virtual + 7) & ~7; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci PM3_WAIT(par, 50); 2198c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); 2208c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3StatisticMode, 0x0); 2218c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3DeltaMode, 0x0); 2228c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RasterizerMode, 0x0); 2238c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMode, 0x0); 2248c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3LineStippleMode, 0x0); 2258c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0); 2268c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3GIDMode, 0x0); 2278c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3DepthMode, 0x0); 2288c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3StencilMode, 0x0); 2298c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3StencilData, 0x0); 2308c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0); 2318c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0); 2328c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0); 2338c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0); 2348c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureReadMode, 0x0); 2358c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3LUTMode, 0x0); 2368c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0); 2378c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0); 2388c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0); 2398c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0); 2408c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0); 2418c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0); 2428c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0); 2438c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FogMode, 0x0); 2448c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0); 2458c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0); 2468c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3AntialiasMode, 0x0); 2478c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3YUVMode, 0x0); 2488c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0); 2498c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0); 2508c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3DitherMode, 0x0); 2518c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0); 2528c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RouterMode, 0x0); 2538c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Window, 0x0); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Config2D, 0x0); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3XBias, 0x0); 2608c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3YBias, 0x0); 2618c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3DeltaControl, 0x0); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadEnables, 2668c2ecf20Sopenharmony_ci PM3FBDestReadEnables_E(0xff) | 2678c2ecf20Sopenharmony_ci PM3FBDestReadEnables_R(0xff) | 2688c2ecf20Sopenharmony_ci PM3FBDestReadEnables_ReferenceAlpha(0xff)); 2698c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0); 2708c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0); 2718c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0, 2728c2ecf20Sopenharmony_ci PM3FBDestReadBufferWidth_Width(width)); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadMode, 2758c2ecf20Sopenharmony_ci PM3FBDestReadMode_ReadEnable | 2768c2ecf20Sopenharmony_ci PM3FBDestReadMode_Enable0); 2778c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0); 2788c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0); 2798c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth, 2808c2ecf20Sopenharmony_ci PM3FBSourceReadBufferWidth_Width(width)); 2818c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadMode, 2828c2ecf20Sopenharmony_ci PM3FBSourceReadMode_Blocking | 2838c2ecf20Sopenharmony_ci PM3FBSourceReadMode_ReadEnable); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci PM3_WAIT(par, 2); 2868c2ecf20Sopenharmony_ci { 2878c2ecf20Sopenharmony_ci /* invert bits in bitmask */ 2888c2ecf20Sopenharmony_ci unsigned long rm = 1 | (3 << 7); 2898c2ecf20Sopenharmony_ci switch (info->var.bits_per_pixel) { 2908c2ecf20Sopenharmony_ci case 8: 2918c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3PixelSize, 2928c2ecf20Sopenharmony_ci PM3PixelSize_GLOBAL_8BIT); 2938c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 2948c2ecf20Sopenharmony_ci rm |= 3 << 15; 2958c2ecf20Sopenharmony_ci#endif 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci case 16: 2988c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3PixelSize, 2998c2ecf20Sopenharmony_ci PM3PixelSize_GLOBAL_16BIT); 3008c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 3018c2ecf20Sopenharmony_ci rm |= 2 << 15; 3028c2ecf20Sopenharmony_ci#endif 3038c2ecf20Sopenharmony_ci break; 3048c2ecf20Sopenharmony_ci case 32: 3058c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3PixelSize, 3068c2ecf20Sopenharmony_ci PM3PixelSize_GLOBAL_32BIT); 3078c2ecf20Sopenharmony_ci break; 3088c2ecf20Sopenharmony_ci default: 3098c2ecf20Sopenharmony_ci DPRINTK("Unsupported depth %d\n", 3108c2ecf20Sopenharmony_ci info->var.bits_per_pixel); 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RasterizerMode, rm); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci PM3_WAIT(par, 20); 3178c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff); 3188c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff); 3198c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBWriteMode, 3208c2ecf20Sopenharmony_ci PM3FBWriteMode_WriteEnable | 3218c2ecf20Sopenharmony_ci PM3FBWriteMode_OpaqueSpan | 3228c2ecf20Sopenharmony_ci PM3FBWriteMode_Enable0); 3238c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0); 3248c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0); 3258c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBWriteBufferWidth0, 3268c2ecf20Sopenharmony_ci PM3FBWriteBufferWidth_Width(width)); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0); 3298c2ecf20Sopenharmony_ci { 3308c2ecf20Sopenharmony_ci /* size in lines of FB */ 3318c2ecf20Sopenharmony_ci unsigned long sofb = info->screen_size / 3328c2ecf20Sopenharmony_ci info->fix.line_length; 3338c2ecf20Sopenharmony_ci if (sofb > 4095) 3348c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095); 3358c2ecf20Sopenharmony_ci else 3368c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci switch (info->var.bits_per_pixel) { 3398c2ecf20Sopenharmony_ci case 8: 3408c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3DitherMode, 3418c2ecf20Sopenharmony_ci (1 << 10) | (2 << 3)); 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci case 16: 3448c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3DitherMode, 3458c2ecf20Sopenharmony_ci (1 << 10) | (1 << 3)); 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci case 32: 3488c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3DitherMode, 3498c2ecf20Sopenharmony_ci (1 << 10) | (0 << 3)); 3508c2ecf20Sopenharmony_ci break; 3518c2ecf20Sopenharmony_ci default: 3528c2ecf20Sopenharmony_ci DPRINTK("Unsupported depth %d\n", 3538c2ecf20Sopenharmony_ci info->var.bits_per_pixel); 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3dXDom, 0x0); 3598c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3dXSub, 0x0); 3608c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3dY, 1 << 16); 3618c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3StartXDom, 0x0); 3628c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3StartXSub, 0x0); 3638c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3StartY, 0x0); 3648c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Count, 0x0); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* Disable LocalBuffer. better safe than sorry */ 3678c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0); 3688c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0); 3698c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0); 3708c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3LBWriteMode, 0x0); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci pm3fb_sync(info); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void pm3fb_fillrect(struct fb_info *info, 3768c2ecf20Sopenharmony_ci const struct fb_fillrect *region) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 3798c2ecf20Sopenharmony_ci struct fb_fillrect modded; 3808c2ecf20Sopenharmony_ci int vxres, vyres; 3818c2ecf20Sopenharmony_ci int rop; 3828c2ecf20Sopenharmony_ci u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? 3838c2ecf20Sopenharmony_ci ((u32 *)info->pseudo_palette)[region->color] : region->color; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 3868c2ecf20Sopenharmony_ci return; 3878c2ecf20Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 3888c2ecf20Sopenharmony_ci cfb_fillrect(info, region); 3898c2ecf20Sopenharmony_ci return; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci if (region->rop == ROP_COPY ) 3928c2ecf20Sopenharmony_ci rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */ 3938c2ecf20Sopenharmony_ci else 3948c2ecf20Sopenharmony_ci rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */ 3958c2ecf20Sopenharmony_ci PM3Config2D_FBDestReadEnable; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci vxres = info->var.xres_virtual; 3988c2ecf20Sopenharmony_ci vyres = info->var.yres_virtual; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci memcpy(&modded, region, sizeof(struct fb_fillrect)); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (!modded.width || !modded.height || 4038c2ecf20Sopenharmony_ci modded.dx >= vxres || modded.dy >= vyres) 4048c2ecf20Sopenharmony_ci return; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (modded.dx + modded.width > vxres) 4078c2ecf20Sopenharmony_ci modded.width = vxres - modded.dx; 4088c2ecf20Sopenharmony_ci if (modded.dy + modded.height > vyres) 4098c2ecf20Sopenharmony_ci modded.height = vyres - modded.dy; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 8) 4128c2ecf20Sopenharmony_ci color |= color << 8; 4138c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel <= 16) 4148c2ecf20Sopenharmony_ci color |= color << 16; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci PM3_WAIT(par, 4); 4178c2ecf20Sopenharmony_ci /* ROP Ox3 is GXcopy */ 4188c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Config2D, 4198c2ecf20Sopenharmony_ci PM3Config2D_UseConstantSource | 4208c2ecf20Sopenharmony_ci PM3Config2D_ForegroundROPEnable | 4218c2ecf20Sopenharmony_ci rop | 4228c2ecf20Sopenharmony_ci PM3Config2D_FBWriteEnable); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ForegroundColor, color); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RectanglePosition, 4278c2ecf20Sopenharmony_ci PM3RectanglePosition_XOffset(modded.dx) | 4288c2ecf20Sopenharmony_ci PM3RectanglePosition_YOffset(modded.dy)); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Render2D, 4318c2ecf20Sopenharmony_ci PM3Render2D_XPositive | 4328c2ecf20Sopenharmony_ci PM3Render2D_YPositive | 4338c2ecf20Sopenharmony_ci PM3Render2D_Operation_Normal | 4348c2ecf20Sopenharmony_ci PM3Render2D_SpanOperation | 4358c2ecf20Sopenharmony_ci PM3Render2D_Width(modded.width) | 4368c2ecf20Sopenharmony_ci PM3Render2D_Height(modded.height)); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void pm3fb_copyarea(struct fb_info *info, 4408c2ecf20Sopenharmony_ci const struct fb_copyarea *area) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 4438c2ecf20Sopenharmony_ci struct fb_copyarea modded; 4448c2ecf20Sopenharmony_ci u32 vxres, vyres; 4458c2ecf20Sopenharmony_ci int x_align, o_x, o_y; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 4488c2ecf20Sopenharmony_ci return; 4498c2ecf20Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 4508c2ecf20Sopenharmony_ci cfb_copyarea(info, area); 4518c2ecf20Sopenharmony_ci return; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci memcpy(&modded, area, sizeof(struct fb_copyarea)); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci vxres = info->var.xres_virtual; 4578c2ecf20Sopenharmony_ci vyres = info->var.yres_virtual; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (!modded.width || !modded.height || 4608c2ecf20Sopenharmony_ci modded.sx >= vxres || modded.sy >= vyres || 4618c2ecf20Sopenharmony_ci modded.dx >= vxres || modded.dy >= vyres) 4628c2ecf20Sopenharmony_ci return; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (modded.sx + modded.width > vxres) 4658c2ecf20Sopenharmony_ci modded.width = vxres - modded.sx; 4668c2ecf20Sopenharmony_ci if (modded.dx + modded.width > vxres) 4678c2ecf20Sopenharmony_ci modded.width = vxres - modded.dx; 4688c2ecf20Sopenharmony_ci if (modded.sy + modded.height > vyres) 4698c2ecf20Sopenharmony_ci modded.height = vyres - modded.sy; 4708c2ecf20Sopenharmony_ci if (modded.dy + modded.height > vyres) 4718c2ecf20Sopenharmony_ci modded.height = vyres - modded.dy; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci o_x = modded.sx - modded.dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ 4748c2ecf20Sopenharmony_ci o_y = modded.sy - modded.dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci x_align = (modded.sx & 0x1f); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci PM3_WAIT(par, 6); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Config2D, 4818c2ecf20Sopenharmony_ci PM3Config2D_UserScissorEnable | 4828c2ecf20Sopenharmony_ci PM3Config2D_ForegroundROPEnable | 4838c2ecf20Sopenharmony_ci PM3Config2D_Blocking | 4848c2ecf20Sopenharmony_ci PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */ 4858c2ecf20Sopenharmony_ci PM3Config2D_FBWriteEnable); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMinXY, 4888c2ecf20Sopenharmony_ci ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff)); 4898c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMaxXY, 4908c2ecf20Sopenharmony_ci (((modded.dy + modded.height) & 0x0fff) << 16) | 4918c2ecf20Sopenharmony_ci ((modded.dx + modded.width) & 0x0fff)); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 4948c2ecf20Sopenharmony_ci PM3FBSourceReadBufferOffset_XOffset(o_x) | 4958c2ecf20Sopenharmony_ci PM3FBSourceReadBufferOffset_YOffset(o_y)); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RectanglePosition, 4988c2ecf20Sopenharmony_ci PM3RectanglePosition_XOffset(modded.dx - x_align) | 4998c2ecf20Sopenharmony_ci PM3RectanglePosition_YOffset(modded.dy)); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Render2D, 5028c2ecf20Sopenharmony_ci ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) | 5038c2ecf20Sopenharmony_ci ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) | 5048c2ecf20Sopenharmony_ci PM3Render2D_Operation_Normal | 5058c2ecf20Sopenharmony_ci PM3Render2D_SpanOperation | 5068c2ecf20Sopenharmony_ci PM3Render2D_FBSourceReadEnable | 5078c2ecf20Sopenharmony_ci PM3Render2D_Width(modded.width + x_align) | 5088c2ecf20Sopenharmony_ci PM3Render2D_Height(modded.height)); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 5148c2ecf20Sopenharmony_ci u32 height = image->height; 5158c2ecf20Sopenharmony_ci u32 fgx, bgx; 5168c2ecf20Sopenharmony_ci const u32 *src = (const u32 *)image->data; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 5198c2ecf20Sopenharmony_ci return; 5208c2ecf20Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 5218c2ecf20Sopenharmony_ci cfb_imageblit(info, image); 5228c2ecf20Sopenharmony_ci return; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci switch (info->fix.visual) { 5258c2ecf20Sopenharmony_ci case FB_VISUAL_PSEUDOCOLOR: 5268c2ecf20Sopenharmony_ci fgx = image->fg_color; 5278c2ecf20Sopenharmony_ci bgx = image->bg_color; 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci case FB_VISUAL_TRUECOLOR: 5308c2ecf20Sopenharmony_ci default: 5318c2ecf20Sopenharmony_ci fgx = par->palette[image->fg_color]; 5328c2ecf20Sopenharmony_ci bgx = par->palette[image->bg_color]; 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci if (image->depth != 1) { 5368c2ecf20Sopenharmony_ci cfb_imageblit(info, image); 5378c2ecf20Sopenharmony_ci return; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel == 8) { 5418c2ecf20Sopenharmony_ci fgx |= fgx << 8; 5428c2ecf20Sopenharmony_ci bgx |= bgx << 8; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci if (info->var.bits_per_pixel <= 16) { 5458c2ecf20Sopenharmony_ci fgx |= fgx << 16; 5468c2ecf20Sopenharmony_ci bgx |= bgx << 16; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci PM3_WAIT(par, 7); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ForegroundColor, fgx); 5528c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3BackgroundColor, bgx); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* ROP Ox3 is GXcopy */ 5558c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Config2D, 5568c2ecf20Sopenharmony_ci PM3Config2D_UserScissorEnable | 5578c2ecf20Sopenharmony_ci PM3Config2D_UseConstantSource | 5588c2ecf20Sopenharmony_ci PM3Config2D_ForegroundROPEnable | 5598c2ecf20Sopenharmony_ci PM3Config2D_ForegroundROP(0x3) | 5608c2ecf20Sopenharmony_ci PM3Config2D_OpaqueSpan | 5618c2ecf20Sopenharmony_ci PM3Config2D_FBWriteEnable); 5628c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMinXY, 5638c2ecf20Sopenharmony_ci ((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff)); 5648c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMaxXY, 5658c2ecf20Sopenharmony_ci (((image->dy + image->height) & 0x0fff) << 16) | 5668c2ecf20Sopenharmony_ci ((image->dx + image->width) & 0x0fff)); 5678c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3RectanglePosition, 5688c2ecf20Sopenharmony_ci PM3RectanglePosition_XOffset(image->dx) | 5698c2ecf20Sopenharmony_ci PM3RectanglePosition_YOffset(image->dy)); 5708c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Render2D, 5718c2ecf20Sopenharmony_ci PM3Render2D_XPositive | 5728c2ecf20Sopenharmony_ci PM3Render2D_YPositive | 5738c2ecf20Sopenharmony_ci PM3Render2D_Operation_SyncOnBitMask | 5748c2ecf20Sopenharmony_ci PM3Render2D_SpanOperation | 5758c2ecf20Sopenharmony_ci PM3Render2D_Width(image->width) | 5768c2ecf20Sopenharmony_ci PM3Render2D_Height(image->height)); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci while (height--) { 5808c2ecf20Sopenharmony_ci int width = ((image->width + 7) >> 3) 5818c2ecf20Sopenharmony_ci + info->pixmap.scan_align - 1; 5828c2ecf20Sopenharmony_ci width >>= 2; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci while (width >= PM3_FIFO_SIZE) { 5858c2ecf20Sopenharmony_ci int i = PM3_FIFO_SIZE - 1; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci PM3_WAIT(par, PM3_FIFO_SIZE); 5888c2ecf20Sopenharmony_ci while (i--) { 5898c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3BitMaskPattern, *src); 5908c2ecf20Sopenharmony_ci src++; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci width -= PM3_FIFO_SIZE - 1; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci PM3_WAIT(par, width + 1); 5968c2ecf20Sopenharmony_ci while (width--) { 5978c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3BitMaskPattern, *src); 5988c2ecf20Sopenharmony_ci src++; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci/* end of acceleration functions */ 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci/* 6058c2ecf20Sopenharmony_ci * Hardware Cursor support. 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_cistatic const u8 cursor_bits_lookup[16] = { 6088c2ecf20Sopenharmony_ci 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 6098c2ecf20Sopenharmony_ci 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 6108c2ecf20Sopenharmony_ci}; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic int pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 6158c2ecf20Sopenharmony_ci u8 mode; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (!hwcursor) 6188c2ecf20Sopenharmony_ci return -EINVAL; /* just to force soft_cursor() call */ 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* Too large of a cursor or wrong bpp :-( */ 6218c2ecf20Sopenharmony_ci if (cursor->image.width > 64 || 6228c2ecf20Sopenharmony_ci cursor->image.height > 64 || 6238c2ecf20Sopenharmony_ci cursor->image.depth > 1) 6248c2ecf20Sopenharmony_ci return -EINVAL; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci mode = PM3RD_CursorMode_TYPE_X; 6278c2ecf20Sopenharmony_ci if (cursor->enable) 6288c2ecf20Sopenharmony_ci mode |= PM3RD_CursorMode_CURSOR_ENABLE; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* 6338c2ecf20Sopenharmony_ci * If the cursor is not be changed this means either we want the 6348c2ecf20Sopenharmony_ci * current cursor state (if enable is set) or we want to query what 6358c2ecf20Sopenharmony_ci * we can do with the cursor (if enable is not set) 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ci if (!cursor->set) 6388c2ecf20Sopenharmony_ci return 0; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (cursor->set & FB_CUR_SETPOS) { 6418c2ecf20Sopenharmony_ci int x = cursor->image.dx - info->var.xoffset; 6428c2ecf20Sopenharmony_ci int y = cursor->image.dy - info->var.yoffset; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff); 6458c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf); 6468c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff); 6478c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (cursor->set & FB_CUR_SETHOT) { 6518c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX, 6528c2ecf20Sopenharmony_ci cursor->hot.x & 0x3f); 6538c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY, 6548c2ecf20Sopenharmony_ci cursor->hot.y & 0x3f); 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (cursor->set & FB_CUR_SETCMAP) { 6588c2ecf20Sopenharmony_ci u32 fg_idx = cursor->image.fg_color; 6598c2ecf20Sopenharmony_ci u32 bg_idx = cursor->image.bg_color; 6608c2ecf20Sopenharmony_ci struct fb_cmap cmap = info->cmap; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* the X11 driver says one should use these color registers */ 6638c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39), 6648c2ecf20Sopenharmony_ci cmap.red[fg_idx] >> 8 ); 6658c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40), 6668c2ecf20Sopenharmony_ci cmap.green[fg_idx] >> 8 ); 6678c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41), 6688c2ecf20Sopenharmony_ci cmap.blue[fg_idx] >> 8 ); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42), 6718c2ecf20Sopenharmony_ci cmap.red[bg_idx] >> 8 ); 6728c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43), 6738c2ecf20Sopenharmony_ci cmap.green[bg_idx] >> 8 ); 6748c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44), 6758c2ecf20Sopenharmony_ci cmap.blue[bg_idx] >> 8 ); 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { 6798c2ecf20Sopenharmony_ci u8 *bitmap = (u8 *)cursor->image.data; 6808c2ecf20Sopenharmony_ci u8 *mask = (u8 *)cursor->mask; 6818c2ecf20Sopenharmony_ci int i; 6828c2ecf20Sopenharmony_ci int pos = PM3RD_CursorPattern(0); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci for (i = 0; i < cursor->image.height; i++) { 6858c2ecf20Sopenharmony_ci int j = (cursor->image.width + 7) >> 3; 6868c2ecf20Sopenharmony_ci int k = 8 - j; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci for (; j > 0; j--) { 6898c2ecf20Sopenharmony_ci u8 data = *bitmap ^ *mask; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (cursor->rop == ROP_COPY) 6928c2ecf20Sopenharmony_ci data = *mask & *bitmap; 6938c2ecf20Sopenharmony_ci /* Upper 4 bits of bitmap data */ 6948c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 6958c2ecf20Sopenharmony_ci cursor_bits_lookup[data >> 4] | 6968c2ecf20Sopenharmony_ci (cursor_bits_lookup[*mask >> 4] << 1)); 6978c2ecf20Sopenharmony_ci /* Lower 4 bits of bitmap */ 6988c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 6998c2ecf20Sopenharmony_ci cursor_bits_lookup[data & 0xf] | 7008c2ecf20Sopenharmony_ci (cursor_bits_lookup[*mask & 0xf] << 1)); 7018c2ecf20Sopenharmony_ci bitmap++; 7028c2ecf20Sopenharmony_ci mask++; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci for (; k > 0; k--) { 7058c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 0); 7068c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 0); 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci while (pos < PM3RD_CursorPattern(1024)) 7108c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 0); 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci return 0; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci/* write the mode to registers */ 7168c2ecf20Sopenharmony_cistatic void pm3fb_write_mode(struct fb_info *info) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 7198c2ecf20Sopenharmony_ci char tempsync = 0x00; 7208c2ecf20Sopenharmony_ci char tempmisc = 0x00; 7218c2ecf20Sopenharmony_ci const u32 hsstart = info->var.right_margin; 7228c2ecf20Sopenharmony_ci const u32 hsend = hsstart + info->var.hsync_len; 7238c2ecf20Sopenharmony_ci const u32 hbend = hsend + info->var.left_margin; 7248c2ecf20Sopenharmony_ci const u32 xres = (info->var.xres + 31) & ~31; 7258c2ecf20Sopenharmony_ci const u32 htotal = xres + hbend; 7268c2ecf20Sopenharmony_ci const u32 vsstart = info->var.lower_margin; 7278c2ecf20Sopenharmony_ci const u32 vsend = vsstart + info->var.vsync_len; 7288c2ecf20Sopenharmony_ci const u32 vbend = vsend + info->var.upper_margin; 7298c2ecf20Sopenharmony_ci const u32 vtotal = info->var.yres + vbend; 7308c2ecf20Sopenharmony_ci const u32 width = (info->var.xres_virtual + 7) & ~7; 7318c2ecf20Sopenharmony_ci const unsigned bpp = info->var.bits_per_pixel; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci PM3_WAIT(par, 20); 7348c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff); 7358c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Aperture0, 0x00000000); 7368c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3Aperture1, 0x00000000); 7378c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3FIFODis, 0x00000007); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3HTotal, 7408c2ecf20Sopenharmony_ci pm3fb_shift_bpp(bpp, htotal - 1)); 7418c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3HsEnd, 7428c2ecf20Sopenharmony_ci pm3fb_shift_bpp(bpp, hsend)); 7438c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3HsStart, 7448c2ecf20Sopenharmony_ci pm3fb_shift_bpp(bpp, hsstart)); 7458c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3HbEnd, 7468c2ecf20Sopenharmony_ci pm3fb_shift_bpp(bpp, hbend)); 7478c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3HgEnd, 7488c2ecf20Sopenharmony_ci pm3fb_shift_bpp(bpp, hbend)); 7498c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ScreenStride, 7508c2ecf20Sopenharmony_ci pm3fb_shift_bpp(bpp, width)); 7518c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3VTotal, vtotal - 1); 7528c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3VsEnd, vsend - 1); 7538c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3VsStart, vsstart - 1); 7548c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3VbEnd, vbend); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci switch (bpp) { 7578c2ecf20Sopenharmony_ci case 8: 7588c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 7598c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_8BIT); 7608c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 7618c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_8BIT); 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci case 16: 7658c2ecf20Sopenharmony_ci#ifndef __BIG_ENDIAN 7668c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 7678c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_16BIT); 7688c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 7698c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_16BIT); 7708c2ecf20Sopenharmony_ci#else 7718c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 7728c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_16BIT | 7738c2ecf20Sopenharmony_ci PM3ByApertureMode_BYTESWAP_BADC); 7748c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 7758c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_16BIT | 7768c2ecf20Sopenharmony_ci PM3ByApertureMode_BYTESWAP_BADC); 7778c2ecf20Sopenharmony_ci#endif /* ! __BIG_ENDIAN */ 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci case 32: 7818c2ecf20Sopenharmony_ci#ifndef __BIG_ENDIAN 7828c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 7838c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_32BIT); 7848c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 7858c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_32BIT); 7868c2ecf20Sopenharmony_ci#else 7878c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 7888c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_32BIT | 7898c2ecf20Sopenharmony_ci PM3ByApertureMode_BYTESWAP_DCBA); 7908c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 7918c2ecf20Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_32BIT | 7928c2ecf20Sopenharmony_ci PM3ByApertureMode_BYTESWAP_DCBA); 7938c2ecf20Sopenharmony_ci#endif /* ! __BIG_ENDIAN */ 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci default: 7978c2ecf20Sopenharmony_ci DPRINTK("Unsupported depth %d\n", bpp); 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci /* 8028c2ecf20Sopenharmony_ci * Oxygen VX1 - it appears that setting PM3VideoControl and 8038c2ecf20Sopenharmony_ci * then PM3RD_SyncControl to the same SYNC settings undoes 8048c2ecf20Sopenharmony_ci * any net change - they seem to xor together. Only set the 8058c2ecf20Sopenharmony_ci * sync options in PM3RD_SyncControl. --rmk 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ci { 8088c2ecf20Sopenharmony_ci unsigned int video = par->video; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci video &= ~(PM3VideoControl_HSYNC_MASK | 8118c2ecf20Sopenharmony_ci PM3VideoControl_VSYNC_MASK); 8128c2ecf20Sopenharmony_ci video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 8138c2ecf20Sopenharmony_ci PM3VideoControl_VSYNC_ACTIVE_HIGH; 8148c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3VideoControl, video); 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3VClkCtl, 8178c2ecf20Sopenharmony_ci (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC)); 8188c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ScreenBase, par->base); 8198c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ChipConfig, 8208c2ecf20Sopenharmony_ci (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD)); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci wmb(); 8238c2ecf20Sopenharmony_ci { 8248c2ecf20Sopenharmony_ci unsigned char m; /* ClkPreScale */ 8258c2ecf20Sopenharmony_ci unsigned char n; /* ClkFeedBackScale */ 8268c2ecf20Sopenharmony_ci unsigned char p; /* ClkPostScale */ 8278c2ecf20Sopenharmony_ci unsigned long pixclock = PICOS2KHZ(info->var.pixclock); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci (void)pm3fb_calculate_clock(pixclock, &m, &n, &p); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n", 8328c2ecf20Sopenharmony_ci pixclock, (int) m, (int) n, (int) p); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m); 8358c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n); 8368c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p); 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci /* 8398c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00); 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_ci /* 8428c2ecf20Sopenharmony_ci PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00); 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci if ((par->video & PM3VideoControl_HSYNC_MASK) == 8458c2ecf20Sopenharmony_ci PM3VideoControl_HSYNC_ACTIVE_HIGH) 8468c2ecf20Sopenharmony_ci tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; 8478c2ecf20Sopenharmony_ci if ((par->video & PM3VideoControl_VSYNC_MASK) == 8488c2ecf20Sopenharmony_ci PM3VideoControl_VSYNC_ACTIVE_HIGH) 8498c2ecf20Sopenharmony_ci tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync); 8528c2ecf20Sopenharmony_ci DPRINTK("PM3RD_SyncControl: %d\n", tempsync); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci switch (pm3fb_depth(&info->var)) { 8578c2ecf20Sopenharmony_ci case 8: 8588c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 8598c2ecf20Sopenharmony_ci PM3RD_PixelSize_8_BIT_PIXELS); 8608c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 8618c2ecf20Sopenharmony_ci PM3RD_ColorFormat_CI8_COLOR | 8628c2ecf20Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 8638c2ecf20Sopenharmony_ci tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci case 12: 8668c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 8678c2ecf20Sopenharmony_ci PM3RD_PixelSize_16_BIT_PIXELS); 8688c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 8698c2ecf20Sopenharmony_ci PM3RD_ColorFormat_4444_COLOR | 8708c2ecf20Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 8718c2ecf20Sopenharmony_ci PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 8728c2ecf20Sopenharmony_ci tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 8738c2ecf20Sopenharmony_ci PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 8748c2ecf20Sopenharmony_ci break; 8758c2ecf20Sopenharmony_ci case 15: 8768c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 8778c2ecf20Sopenharmony_ci PM3RD_PixelSize_16_BIT_PIXELS); 8788c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 8798c2ecf20Sopenharmony_ci PM3RD_ColorFormat_5551_FRONT_COLOR | 8808c2ecf20Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 8818c2ecf20Sopenharmony_ci PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 8828c2ecf20Sopenharmony_ci tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 8838c2ecf20Sopenharmony_ci PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 8848c2ecf20Sopenharmony_ci break; 8858c2ecf20Sopenharmony_ci case 16: 8868c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 8878c2ecf20Sopenharmony_ci PM3RD_PixelSize_16_BIT_PIXELS); 8888c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 8898c2ecf20Sopenharmony_ci PM3RD_ColorFormat_565_FRONT_COLOR | 8908c2ecf20Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 8918c2ecf20Sopenharmony_ci PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 8928c2ecf20Sopenharmony_ci tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 8938c2ecf20Sopenharmony_ci PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 8948c2ecf20Sopenharmony_ci break; 8958c2ecf20Sopenharmony_ci case 32: 8968c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 8978c2ecf20Sopenharmony_ci PM3RD_PixelSize_32_BIT_PIXELS); 8988c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 8998c2ecf20Sopenharmony_ci PM3RD_ColorFormat_8888_COLOR | 9008c2ecf20Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 9018c2ecf20Sopenharmony_ci tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 9028c2ecf20Sopenharmony_ci PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 9038c2ecf20Sopenharmony_ci break; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc); 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* 9098c2ecf20Sopenharmony_ci * hardware independent functions 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_cistatic int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci u32 lpitch; 9148c2ecf20Sopenharmony_ci unsigned bpp = var->red.length + var->green.length 9158c2ecf20Sopenharmony_ci + var->blue.length + var->transp.length; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (bpp != var->bits_per_pixel) { 9188c2ecf20Sopenharmony_ci /* set predefined mode for bits_per_pixel settings */ 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 9218c2ecf20Sopenharmony_ci case 8: 9228c2ecf20Sopenharmony_ci var->red.length = 8; 9238c2ecf20Sopenharmony_ci var->green.length = 8; 9248c2ecf20Sopenharmony_ci var->blue.length = 8; 9258c2ecf20Sopenharmony_ci var->red.offset = 0; 9268c2ecf20Sopenharmony_ci var->green.offset = 0; 9278c2ecf20Sopenharmony_ci var->blue.offset = 0; 9288c2ecf20Sopenharmony_ci var->transp.offset = 0; 9298c2ecf20Sopenharmony_ci var->transp.length = 0; 9308c2ecf20Sopenharmony_ci break; 9318c2ecf20Sopenharmony_ci case 16: 9328c2ecf20Sopenharmony_ci var->red.length = 5; 9338c2ecf20Sopenharmony_ci var->blue.length = 5; 9348c2ecf20Sopenharmony_ci var->green.length = 6; 9358c2ecf20Sopenharmony_ci var->transp.length = 0; 9368c2ecf20Sopenharmony_ci break; 9378c2ecf20Sopenharmony_ci case 32: 9388c2ecf20Sopenharmony_ci var->red.length = 8; 9398c2ecf20Sopenharmony_ci var->green.length = 8; 9408c2ecf20Sopenharmony_ci var->blue.length = 8; 9418c2ecf20Sopenharmony_ci var->transp.length = 8; 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci default: 9448c2ecf20Sopenharmony_ci DPRINTK("depth not supported: %u\n", 9458c2ecf20Sopenharmony_ci var->bits_per_pixel); 9468c2ecf20Sopenharmony_ci return -EINVAL; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci /* it is assumed BGRA order */ 9508c2ecf20Sopenharmony_ci if (var->bits_per_pixel > 8 ) { 9518c2ecf20Sopenharmony_ci var->blue.offset = 0; 9528c2ecf20Sopenharmony_ci var->green.offset = var->blue.length; 9538c2ecf20Sopenharmony_ci var->red.offset = var->green.offset + var->green.length; 9548c2ecf20Sopenharmony_ci var->transp.offset = var->red.offset + var->red.length; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci var->height = -1; 9578c2ecf20Sopenharmony_ci var->width = -1; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (var->xres != var->xres_virtual) { 9608c2ecf20Sopenharmony_ci DPRINTK("virtual x resolution != " 9618c2ecf20Sopenharmony_ci "physical x resolution not supported\n"); 9628c2ecf20Sopenharmony_ci return -EINVAL; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (var->yres > var->yres_virtual) { 9668c2ecf20Sopenharmony_ci DPRINTK("virtual y resolution < " 9678c2ecf20Sopenharmony_ci "physical y resolution not possible\n"); 9688c2ecf20Sopenharmony_ci return -EINVAL; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (var->xoffset) { 9728c2ecf20Sopenharmony_ci DPRINTK("xoffset not supported\n"); 9738c2ecf20Sopenharmony_ci return -EINVAL; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 9778c2ecf20Sopenharmony_ci DPRINTK("interlace not supported\n"); 9788c2ecf20Sopenharmony_ci return -EINVAL; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ 9828c2ecf20Sopenharmony_ci lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (var->xres < 200 || var->xres > 2048) { 9858c2ecf20Sopenharmony_ci DPRINTK("width not supported: %u\n", var->xres); 9868c2ecf20Sopenharmony_ci return -EINVAL; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (var->yres < 200 || var->yres > 4095) { 9908c2ecf20Sopenharmony_ci DPRINTK("height not supported: %u\n", var->yres); 9918c2ecf20Sopenharmony_ci return -EINVAL; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (lpitch * var->yres_virtual > info->fix.smem_len) { 9958c2ecf20Sopenharmony_ci DPRINTK("no memory for screen (%ux%ux%u)\n", 9968c2ecf20Sopenharmony_ci var->xres, var->yres_virtual, var->bits_per_pixel); 9978c2ecf20Sopenharmony_ci return -EINVAL; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { 10018c2ecf20Sopenharmony_ci DPRINTK("pixclock too high (%ldKHz)\n", 10028c2ecf20Sopenharmony_ci PICOS2KHZ(var->pixclock)); 10038c2ecf20Sopenharmony_ci return -EINVAL; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci var->accel_flags = 0; /* Can't mmap if this is on */ 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci DPRINTK("Checking graphics mode at %dx%d depth %d\n", 10098c2ecf20Sopenharmony_ci var->xres, var->yres, var->bits_per_pixel); 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic int pm3fb_set_par(struct fb_info *info) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 10168c2ecf20Sopenharmony_ci const u32 xres = (info->var.xres + 31) & ~31; 10178c2ecf20Sopenharmony_ci const unsigned bpp = info->var.bits_per_pixel; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres) 10208c2ecf20Sopenharmony_ci + info->var.xoffset); 10218c2ecf20Sopenharmony_ci par->video = 0; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 10248c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; 10258c2ecf20Sopenharmony_ci else 10268c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 10298c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; 10308c2ecf20Sopenharmony_ci else 10318c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) 10348c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_LINE_DOUBLE_ON; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) 10378c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_ENABLE; 10388c2ecf20Sopenharmony_ci else 10398c2ecf20Sopenharmony_ci DPRINTK("PM3Video disabled\n"); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci switch (bpp) { 10428c2ecf20Sopenharmony_ci case 8: 10438c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_PIXELSIZE_8BIT; 10448c2ecf20Sopenharmony_ci break; 10458c2ecf20Sopenharmony_ci case 16: 10468c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_PIXELSIZE_16BIT; 10478c2ecf20Sopenharmony_ci break; 10488c2ecf20Sopenharmony_ci case 32: 10498c2ecf20Sopenharmony_ci par->video |= PM3VideoControl_PIXELSIZE_32BIT; 10508c2ecf20Sopenharmony_ci break; 10518c2ecf20Sopenharmony_ci default: 10528c2ecf20Sopenharmony_ci DPRINTK("Unsupported depth\n"); 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci info->fix.visual = 10578c2ecf20Sopenharmony_ci (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 10588c2ecf20Sopenharmony_ci info->fix.line_length = ((info->var.xres_virtual + 7) >> 3) * bpp; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci/* pm3fb_clear_memory(info, 0);*/ 10618c2ecf20Sopenharmony_ci pm3fb_clear_colormap(par, 0, 0, 0); 10628c2ecf20Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0); 10638c2ecf20Sopenharmony_ci pm3fb_init_engine(info); 10648c2ecf20Sopenharmony_ci pm3fb_write_mode(info); 10658c2ecf20Sopenharmony_ci return 0; 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, 10698c2ecf20Sopenharmony_ci unsigned blue, unsigned transp, 10708c2ecf20Sopenharmony_ci struct fb_info *info) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (regno >= 256) /* no. of hw registers */ 10758c2ecf20Sopenharmony_ci return -EINVAL; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* grayscale works only partially under directcolor */ 10788c2ecf20Sopenharmony_ci /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 10798c2ecf20Sopenharmony_ci if (info->var.grayscale) 10808c2ecf20Sopenharmony_ci red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* Directcolor: 10838c2ecf20Sopenharmony_ci * var->{color}.offset contains start of bitfield 10848c2ecf20Sopenharmony_ci * var->{color}.length contains length of bitfield 10858c2ecf20Sopenharmony_ci * {hardwarespecific} contains width of DAC 10868c2ecf20Sopenharmony_ci * pseudo_palette[X] is programmed to (X << red.offset) | 10878c2ecf20Sopenharmony_ci * (X << green.offset) | 10888c2ecf20Sopenharmony_ci * (X << blue.offset) 10898c2ecf20Sopenharmony_ci * RAMDAC[X] is programmed to (red, green, blue) 10908c2ecf20Sopenharmony_ci * color depth = SUM(var->{color}.length) 10918c2ecf20Sopenharmony_ci * 10928c2ecf20Sopenharmony_ci * Pseudocolor: 10938c2ecf20Sopenharmony_ci * var->{color}.offset is 0 10948c2ecf20Sopenharmony_ci * var->{color}.length contains width of DAC or the number 10958c2ecf20Sopenharmony_ci * of unique colors available (color depth) 10968c2ecf20Sopenharmony_ci * pseudo_palette is not used 10978c2ecf20Sopenharmony_ci * RAMDAC[X] is programmed to (red, green, blue) 10988c2ecf20Sopenharmony_ci * color depth = var->{color}.length 10998c2ecf20Sopenharmony_ci */ 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* 11028c2ecf20Sopenharmony_ci * This is the point where the color is converted to something that 11038c2ecf20Sopenharmony_ci * is acceptable by the hardware. 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_ci#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) 11068c2ecf20Sopenharmony_ci red = CNVT_TOHW(red, info->var.red.length); 11078c2ecf20Sopenharmony_ci green = CNVT_TOHW(green, info->var.green.length); 11088c2ecf20Sopenharmony_ci blue = CNVT_TOHW(blue, info->var.blue.length); 11098c2ecf20Sopenharmony_ci transp = CNVT_TOHW(transp, info->var.transp.length); 11108c2ecf20Sopenharmony_ci#undef CNVT_TOHW 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR || 11138c2ecf20Sopenharmony_ci info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 11148c2ecf20Sopenharmony_ci u32 v; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (regno >= 16) 11178c2ecf20Sopenharmony_ci return -EINVAL; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci v = (red << info->var.red.offset) | 11208c2ecf20Sopenharmony_ci (green << info->var.green.offset) | 11218c2ecf20Sopenharmony_ci (blue << info->var.blue.offset) | 11228c2ecf20Sopenharmony_ci (transp << info->var.transp.offset); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci switch (info->var.bits_per_pixel) { 11258c2ecf20Sopenharmony_ci case 8: 11268c2ecf20Sopenharmony_ci break; 11278c2ecf20Sopenharmony_ci case 16: 11288c2ecf20Sopenharmony_ci case 32: 11298c2ecf20Sopenharmony_ci ((u32 *)(info->pseudo_palette))[regno] = v; 11308c2ecf20Sopenharmony_ci break; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci return 0; 11338c2ecf20Sopenharmony_ci } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) 11348c2ecf20Sopenharmony_ci pm3fb_set_color(par, regno, red, green, blue); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return 0; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic int pm3fb_pan_display(struct fb_var_screeninfo *var, 11408c2ecf20Sopenharmony_ci struct fb_info *info) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 11438c2ecf20Sopenharmony_ci const u32 xres = (info->var.xres + 31) & ~31; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci par->base = pm3fb_shift_bpp(info->var.bits_per_pixel, 11468c2ecf20Sopenharmony_ci (var->yoffset * xres) 11478c2ecf20Sopenharmony_ci + var->xoffset); 11488c2ecf20Sopenharmony_ci PM3_WAIT(par, 1); 11498c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3ScreenBase, par->base); 11508c2ecf20Sopenharmony_ci return 0; 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic int pm3fb_blank(int blank_mode, struct fb_info *info) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 11568c2ecf20Sopenharmony_ci u32 video = par->video; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci /* 11598c2ecf20Sopenharmony_ci * Oxygen VX1 - it appears that setting PM3VideoControl and 11608c2ecf20Sopenharmony_ci * then PM3RD_SyncControl to the same SYNC settings undoes 11618c2ecf20Sopenharmony_ci * any net change - they seem to xor together. Only set the 11628c2ecf20Sopenharmony_ci * sync options in PM3RD_SyncControl. --rmk 11638c2ecf20Sopenharmony_ci */ 11648c2ecf20Sopenharmony_ci video &= ~(PM3VideoControl_HSYNC_MASK | 11658c2ecf20Sopenharmony_ci PM3VideoControl_VSYNC_MASK); 11668c2ecf20Sopenharmony_ci video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 11678c2ecf20Sopenharmony_ci PM3VideoControl_VSYNC_ACTIVE_HIGH; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci switch (blank_mode) { 11708c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 11718c2ecf20Sopenharmony_ci video |= PM3VideoControl_ENABLE; 11728c2ecf20Sopenharmony_ci break; 11738c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: 11748c2ecf20Sopenharmony_ci video &= ~PM3VideoControl_ENABLE; 11758c2ecf20Sopenharmony_ci break; 11768c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 11778c2ecf20Sopenharmony_ci video &= ~(PM3VideoControl_HSYNC_MASK | 11788c2ecf20Sopenharmony_ci PM3VideoControl_BLANK_ACTIVE_LOW); 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 11818c2ecf20Sopenharmony_ci video &= ~(PM3VideoControl_VSYNC_MASK | 11828c2ecf20Sopenharmony_ci PM3VideoControl_BLANK_ACTIVE_LOW); 11838c2ecf20Sopenharmony_ci break; 11848c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 11858c2ecf20Sopenharmony_ci video &= ~(PM3VideoControl_HSYNC_MASK | 11868c2ecf20Sopenharmony_ci PM3VideoControl_VSYNC_MASK | 11878c2ecf20Sopenharmony_ci PM3VideoControl_BLANK_ACTIVE_LOW); 11888c2ecf20Sopenharmony_ci break; 11898c2ecf20Sopenharmony_ci default: 11908c2ecf20Sopenharmony_ci DPRINTK("Unsupported blanking %d\n", blank_mode); 11918c2ecf20Sopenharmony_ci return 1; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci PM3_WAIT(par, 1); 11958c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3VideoControl, video); 11968c2ecf20Sopenharmony_ci return 0; 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* 12008c2ecf20Sopenharmony_ci * Frame buffer operations 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic const struct fb_ops pm3fb_ops = { 12048c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12058c2ecf20Sopenharmony_ci .fb_check_var = pm3fb_check_var, 12068c2ecf20Sopenharmony_ci .fb_set_par = pm3fb_set_par, 12078c2ecf20Sopenharmony_ci .fb_setcolreg = pm3fb_setcolreg, 12088c2ecf20Sopenharmony_ci .fb_pan_display = pm3fb_pan_display, 12098c2ecf20Sopenharmony_ci .fb_fillrect = pm3fb_fillrect, 12108c2ecf20Sopenharmony_ci .fb_copyarea = pm3fb_copyarea, 12118c2ecf20Sopenharmony_ci .fb_imageblit = pm3fb_imageblit, 12128c2ecf20Sopenharmony_ci .fb_blank = pm3fb_blank, 12138c2ecf20Sopenharmony_ci .fb_sync = pm3fb_sync, 12148c2ecf20Sopenharmony_ci .fb_cursor = pm3fb_cursor, 12158c2ecf20Sopenharmony_ci}; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- */ 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci /* 12208c2ecf20Sopenharmony_ci * Initialization 12218c2ecf20Sopenharmony_ci */ 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci/* mmio register are already mapped when this function is called */ 12248c2ecf20Sopenharmony_ci/* the pm3fb_fix.smem_start is also set */ 12258c2ecf20Sopenharmony_cistatic unsigned long pm3fb_size_memory(struct pm3_par *par) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci unsigned long memsize = 0; 12288c2ecf20Sopenharmony_ci unsigned long tempBypass, i, temp1, temp2; 12298c2ecf20Sopenharmony_ci unsigned char __iomem *screen_mem; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ 12328c2ecf20Sopenharmony_ci /* Linear frame buffer - request region and map it. */ 12338c2ecf20Sopenharmony_ci if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 12348c2ecf20Sopenharmony_ci "pm3fb smem")) { 12358c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 12368c2ecf20Sopenharmony_ci return 0; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci screen_mem = 12398c2ecf20Sopenharmony_ci ioremap(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 12408c2ecf20Sopenharmony_ci if (!screen_mem) { 12418c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 12428c2ecf20Sopenharmony_ci release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 12438c2ecf20Sopenharmony_ci return 0; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* TODO: card-specific stuff, *before* accessing *any* FB memory */ 12478c2ecf20Sopenharmony_ci /* For Appian Jeronimo 2000 board second head */ 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci PM3_WAIT(par, 1); 12548c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* pm3 split up memory, replicates, and do a lot of 12578c2ecf20Sopenharmony_ci * nasty stuff IMHO ;-) 12588c2ecf20Sopenharmony_ci */ 12598c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 12608c2ecf20Sopenharmony_ci fb_writel(i * 0x00345678, 12618c2ecf20Sopenharmony_ci (screen_mem + (i * 1048576))); 12628c2ecf20Sopenharmony_ci mb(); 12638c2ecf20Sopenharmony_ci temp1 = fb_readl((screen_mem + (i * 1048576))); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* Let's check for wrapover, write will fail at 16MB boundary */ 12668c2ecf20Sopenharmony_ci if (temp1 == (i * 0x00345678)) 12678c2ecf20Sopenharmony_ci memsize = i; 12688c2ecf20Sopenharmony_ci else 12698c2ecf20Sopenharmony_ci break; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci DPRINTK("First detect pass already got %ld MB\n", memsize + 1); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci if (memsize + 1 == i) { 12758c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 12768c2ecf20Sopenharmony_ci /* Clear first 32MB ; 0 is 0, no need to byteswap */ 12778c2ecf20Sopenharmony_ci writel(0x0000000, (screen_mem + (i * 1048576))); 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci wmb(); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci for (i = 32; i < 64; i++) { 12828c2ecf20Sopenharmony_ci fb_writel(i * 0x00345678, 12838c2ecf20Sopenharmony_ci (screen_mem + (i * 1048576))); 12848c2ecf20Sopenharmony_ci mb(); 12858c2ecf20Sopenharmony_ci temp1 = 12868c2ecf20Sopenharmony_ci fb_readl((screen_mem + (i * 1048576))); 12878c2ecf20Sopenharmony_ci temp2 = 12888c2ecf20Sopenharmony_ci fb_readl((screen_mem + ((i - 32) * 1048576))); 12898c2ecf20Sopenharmony_ci /* different value, different RAM... */ 12908c2ecf20Sopenharmony_ci if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) 12918c2ecf20Sopenharmony_ci memsize = i; 12928c2ecf20Sopenharmony_ci else 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci DPRINTK("Second detect pass got %ld MB\n", memsize + 1); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci PM3_WAIT(par, 1); 12998c2ecf20Sopenharmony_ci PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci iounmap(screen_mem); 13028c2ecf20Sopenharmony_ci release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 13038c2ecf20Sopenharmony_ci memsize = 1048576 * (memsize + 1); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci DPRINTK("Returning 0x%08lx bytes\n", memsize); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci return memsize; 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic int pm3fb_probe(struct pci_dev *dev, const struct pci_device_id *ent) 13118c2ecf20Sopenharmony_ci{ 13128c2ecf20Sopenharmony_ci struct fb_info *info; 13138c2ecf20Sopenharmony_ci struct pm3_par *par; 13148c2ecf20Sopenharmony_ci struct device *device = &dev->dev; /* for pci drivers */ 13158c2ecf20Sopenharmony_ci int err; 13168c2ecf20Sopenharmony_ci int retval = -ENXIO; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci err = pci_enable_device(dev); 13198c2ecf20Sopenharmony_ci if (err) { 13208c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); 13218c2ecf20Sopenharmony_ci return err; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci /* 13248c2ecf20Sopenharmony_ci * Dynamically allocate info and par 13258c2ecf20Sopenharmony_ci */ 13268c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct pm3_par), device); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci if (!info) 13298c2ecf20Sopenharmony_ci return -ENOMEM; 13308c2ecf20Sopenharmony_ci par = info->par; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* 13338c2ecf20Sopenharmony_ci * Here we set the screen_base to the virtual memory address 13348c2ecf20Sopenharmony_ci * for the framebuffer. 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ci pm3fb_fix.mmio_start = pci_resource_start(dev, 0); 13378c2ecf20Sopenharmony_ci pm3fb_fix.mmio_len = PM3_REGS_SIZE; 13388c2ecf20Sopenharmony_ci#if defined(__BIG_ENDIAN) 13398c2ecf20Sopenharmony_ci pm3fb_fix.mmio_start += PM3_REGS_SIZE; 13408c2ecf20Sopenharmony_ci DPRINTK("Adjusting register base for big-endian.\n"); 13418c2ecf20Sopenharmony_ci#endif 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* Registers - request region and map it. */ 13448c2ecf20Sopenharmony_ci if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, 13458c2ecf20Sopenharmony_ci "pm3fb regbase")) { 13468c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n"); 13478c2ecf20Sopenharmony_ci goto err_exit_neither; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci par->v_regs = 13508c2ecf20Sopenharmony_ci ioremap(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 13518c2ecf20Sopenharmony_ci if (!par->v_regs) { 13528c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n", 13538c2ecf20Sopenharmony_ci pm3fb_fix.id); 13548c2ecf20Sopenharmony_ci release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 13558c2ecf20Sopenharmony_ci goto err_exit_neither; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci /* Linear frame buffer - request region and map it. */ 13598c2ecf20Sopenharmony_ci pm3fb_fix.smem_start = pci_resource_start(dev, 1); 13608c2ecf20Sopenharmony_ci pm3fb_fix.smem_len = pm3fb_size_memory(par); 13618c2ecf20Sopenharmony_ci if (!pm3fb_fix.smem_len) { 13628c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); 13638c2ecf20Sopenharmony_ci goto err_exit_mmio; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 13668c2ecf20Sopenharmony_ci "pm3fb smem")) { 13678c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 13688c2ecf20Sopenharmony_ci goto err_exit_mmio; 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci info->screen_base = ioremap_wc(pm3fb_fix.smem_start, 13718c2ecf20Sopenharmony_ci pm3fb_fix.smem_len); 13728c2ecf20Sopenharmony_ci if (!info->screen_base) { 13738c2ecf20Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 13748c2ecf20Sopenharmony_ci release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 13758c2ecf20Sopenharmony_ci goto err_exit_mmio; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci info->screen_size = pm3fb_fix.smem_len; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (!nomtrr) 13808c2ecf20Sopenharmony_ci par->wc_cookie = arch_phys_wc_add(pm3fb_fix.smem_start, 13818c2ecf20Sopenharmony_ci pm3fb_fix.smem_len); 13828c2ecf20Sopenharmony_ci info->fbops = &pm3fb_ops; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci par->video = PM3_READ_REG(par, PM3VideoControl); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci info->fix = pm3fb_fix; 13878c2ecf20Sopenharmony_ci info->pseudo_palette = par->palette; 13888c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT | 13898c2ecf20Sopenharmony_ci FBINFO_HWACCEL_XPAN | 13908c2ecf20Sopenharmony_ci FBINFO_HWACCEL_YPAN | 13918c2ecf20Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | 13928c2ecf20Sopenharmony_ci FBINFO_HWACCEL_IMAGEBLIT | 13938c2ecf20Sopenharmony_ci FBINFO_HWACCEL_FILLRECT; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci if (noaccel) { 13968c2ecf20Sopenharmony_ci printk(KERN_DEBUG "disabling acceleration\n"); 13978c2ecf20Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL); 14008c2ecf20Sopenharmony_ci if (!info->pixmap.addr) { 14018c2ecf20Sopenharmony_ci retval = -ENOMEM; 14028c2ecf20Sopenharmony_ci goto err_exit_pixmap; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci info->pixmap.size = PM3_PIXMAP_SIZE; 14058c2ecf20Sopenharmony_ci info->pixmap.buf_align = 4; 14068c2ecf20Sopenharmony_ci info->pixmap.scan_align = 4; 14078c2ecf20Sopenharmony_ci info->pixmap.access_align = 32; 14088c2ecf20Sopenharmony_ci info->pixmap.flags = FB_PIXMAP_SYSTEM; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci /* 14118c2ecf20Sopenharmony_ci * This should give a reasonable default video mode. The following is 14128c2ecf20Sopenharmony_ci * done when we can set a video mode. 14138c2ecf20Sopenharmony_ci */ 14148c2ecf20Sopenharmony_ci if (!mode_option) 14158c2ecf20Sopenharmony_ci mode_option = "640x480@60"; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (!retval || retval == 4) { 14208c2ecf20Sopenharmony_ci retval = -EINVAL; 14218c2ecf20Sopenharmony_ci goto err_exit_both; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { 14258c2ecf20Sopenharmony_ci retval = -ENOMEM; 14268c2ecf20Sopenharmony_ci goto err_exit_both; 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci /* 14308c2ecf20Sopenharmony_ci * For drivers that can... 14318c2ecf20Sopenharmony_ci */ 14328c2ecf20Sopenharmony_ci pm3fb_check_var(&info->var, info); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (register_framebuffer(info) < 0) { 14358c2ecf20Sopenharmony_ci retval = -EINVAL; 14368c2ecf20Sopenharmony_ci goto err_exit_all; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci fb_info(info, "%s frame buffer device\n", info->fix.id); 14398c2ecf20Sopenharmony_ci pci_set_drvdata(dev, info); 14408c2ecf20Sopenharmony_ci return 0; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci err_exit_all: 14438c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 14448c2ecf20Sopenharmony_ci err_exit_both: 14458c2ecf20Sopenharmony_ci kfree(info->pixmap.addr); 14468c2ecf20Sopenharmony_ci err_exit_pixmap: 14478c2ecf20Sopenharmony_ci iounmap(info->screen_base); 14488c2ecf20Sopenharmony_ci release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 14498c2ecf20Sopenharmony_ci err_exit_mmio: 14508c2ecf20Sopenharmony_ci iounmap(par->v_regs); 14518c2ecf20Sopenharmony_ci release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 14528c2ecf20Sopenharmony_ci err_exit_neither: 14538c2ecf20Sopenharmony_ci framebuffer_release(info); 14548c2ecf20Sopenharmony_ci return retval; 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci /* 14588c2ecf20Sopenharmony_ci * Cleanup 14598c2ecf20Sopenharmony_ci */ 14608c2ecf20Sopenharmony_cistatic void pm3fb_remove(struct pci_dev *dev) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci struct fb_info *info = pci_get_drvdata(dev); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (info) { 14658c2ecf20Sopenharmony_ci struct fb_fix_screeninfo *fix = &info->fix; 14668c2ecf20Sopenharmony_ci struct pm3_par *par = info->par; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci unregister_framebuffer(info); 14698c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci arch_phys_wc_del(par->wc_cookie); 14728c2ecf20Sopenharmony_ci iounmap(info->screen_base); 14738c2ecf20Sopenharmony_ci release_mem_region(fix->smem_start, fix->smem_len); 14748c2ecf20Sopenharmony_ci iounmap(par->v_regs); 14758c2ecf20Sopenharmony_ci release_mem_region(fix->mmio_start, fix->mmio_len); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci kfree(info->pixmap.addr); 14788c2ecf20Sopenharmony_ci framebuffer_release(info); 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci} 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_cistatic const struct pci_device_id pm3fb_id_table[] = { 14838c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_3DLABS, 0x0a, 14848c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 14858c2ecf20Sopenharmony_ci { 0, } 14868c2ecf20Sopenharmony_ci}; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci/* For PCI drivers */ 14898c2ecf20Sopenharmony_cistatic struct pci_driver pm3fb_driver = { 14908c2ecf20Sopenharmony_ci .name = "pm3fb", 14918c2ecf20Sopenharmony_ci .id_table = pm3fb_id_table, 14928c2ecf20Sopenharmony_ci .probe = pm3fb_probe, 14938c2ecf20Sopenharmony_ci .remove = pm3fb_remove, 14948c2ecf20Sopenharmony_ci}; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pm3fb_id_table); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci#ifndef MODULE 14998c2ecf20Sopenharmony_ci /* 15008c2ecf20Sopenharmony_ci * Setup 15018c2ecf20Sopenharmony_ci */ 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci/* 15048c2ecf20Sopenharmony_ci * Only necessary if your driver takes special options, 15058c2ecf20Sopenharmony_ci * otherwise we fall back on the generic fb_setup(). 15068c2ecf20Sopenharmony_ci */ 15078c2ecf20Sopenharmony_cistatic int __init pm3fb_setup(char *options) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci char *this_opt; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci /* Parse user specified options (`video=pm3fb:') */ 15128c2ecf20Sopenharmony_ci if (!options || !*options) 15138c2ecf20Sopenharmony_ci return 0; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 15168c2ecf20Sopenharmony_ci if (!*this_opt) 15178c2ecf20Sopenharmony_ci continue; 15188c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "noaccel", 7)) 15198c2ecf20Sopenharmony_ci noaccel = 1; 15208c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "hwcursor=", 9)) 15218c2ecf20Sopenharmony_ci hwcursor = simple_strtoul(this_opt + 9, NULL, 0); 15228c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "nomtrr", 6)) 15238c2ecf20Sopenharmony_ci nomtrr = 1; 15248c2ecf20Sopenharmony_ci else 15258c2ecf20Sopenharmony_ci mode_option = this_opt; 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci return 0; 15288c2ecf20Sopenharmony_ci} 15298c2ecf20Sopenharmony_ci#endif /* MODULE */ 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_cistatic int __init pm3fb_init(void) 15328c2ecf20Sopenharmony_ci{ 15338c2ecf20Sopenharmony_ci /* 15348c2ecf20Sopenharmony_ci * For kernel boot options (in 'video=pm3fb:<options>' format) 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci#ifndef MODULE 15378c2ecf20Sopenharmony_ci char *option = NULL; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (fb_get_options("pm3fb", &option)) 15408c2ecf20Sopenharmony_ci return -ENODEV; 15418c2ecf20Sopenharmony_ci pm3fb_setup(option); 15428c2ecf20Sopenharmony_ci#endif 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci return pci_register_driver(&pm3fb_driver); 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci#ifdef MODULE 15488c2ecf20Sopenharmony_cistatic void __exit pm3fb_exit(void) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci pci_unregister_driver(&pm3fb_driver); 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cimodule_exit(pm3fb_exit); 15548c2ecf20Sopenharmony_ci#endif 15558c2ecf20Sopenharmony_cimodule_init(pm3fb_init); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cimodule_param(mode_option, charp, 0); 15588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); 15598c2ecf20Sopenharmony_cimodule_param(noaccel, bool, 0); 15608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noaccel, "Disable acceleration"); 15618c2ecf20Sopenharmony_cimodule_param(hwcursor, int, 0644); 15628c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hwcursor, "Enable hardware cursor " 15638c2ecf20Sopenharmony_ci "(1=enable, 0=disable, default=1)"); 15648c2ecf20Sopenharmony_cimodule_param(nomtrr, bool, 0); 15658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Permedia3 framebuffer device driver"); 15688c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1569