162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl> 762306a36Sopenharmony_ci * based on pm2fb.c 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Based on code written by: 1062306a36Sopenharmony_ci * Sven Luther, <luther@dpt-info.u-strasbg.fr> 1162306a36Sopenharmony_ci * Alan Hourihane, <alanh@fairlite.demon.co.uk> 1262306a36Sopenharmony_ci * Russell King, <rmk@arm.linux.org.uk> 1362306a36Sopenharmony_ci * Based on linux/drivers/video/skeletonfb.c: 1462306a36Sopenharmony_ci * Copyright (C) 1997 Geert Uytterhoeven 1562306a36Sopenharmony_ci * Based on linux/driver/video/pm2fb.c: 1662306a36Sopenharmony_ci * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) 1762306a36Sopenharmony_ci * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 2062306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 2162306a36Sopenharmony_ci * more details. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/aperture.h> 2662306a36Sopenharmony_ci#include <linux/module.h> 2762306a36Sopenharmony_ci#include <linux/kernel.h> 2862306a36Sopenharmony_ci#include <linux/errno.h> 2962306a36Sopenharmony_ci#include <linux/string.h> 3062306a36Sopenharmony_ci#include <linux/mm.h> 3162306a36Sopenharmony_ci#include <linux/slab.h> 3262306a36Sopenharmony_ci#include <linux/delay.h> 3362306a36Sopenharmony_ci#include <linux/fb.h> 3462306a36Sopenharmony_ci#include <linux/init.h> 3562306a36Sopenharmony_ci#include <linux/pci.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <video/pm3fb.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#if !defined(CONFIG_PCI) 4062306a36Sopenharmony_ci#error "Only generic PCI cards supported." 4162306a36Sopenharmony_ci#endif 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#undef PM3FB_MASTER_DEBUG 4462306a36Sopenharmony_ci#ifdef PM3FB_MASTER_DEBUG 4562306a36Sopenharmony_ci#define DPRINTK(a, b...) \ 4662306a36Sopenharmony_ci printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b) 4762306a36Sopenharmony_ci#else 4862306a36Sopenharmony_ci#define DPRINTK(a, b...) no_printk(a, ##b) 4962306a36Sopenharmony_ci#endif 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define PM3_PIXMAP_SIZE (2048 * 4) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * Driver data 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistatic int hwcursor = 1; 5762306a36Sopenharmony_cistatic char *mode_option; 5862306a36Sopenharmony_cistatic bool noaccel; 5962306a36Sopenharmony_cistatic bool nomtrr; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * This structure defines the hardware state of the graphics card. Normally 6362306a36Sopenharmony_ci * you place this in a header file in linux/include/video. This file usually 6462306a36Sopenharmony_ci * also includes register information. That allows other driver subsystems 6562306a36Sopenharmony_ci * and userland applications the ability to use the same header file to 6662306a36Sopenharmony_ci * avoid duplicate work and easy porting of software. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_cistruct pm3_par { 6962306a36Sopenharmony_ci unsigned char __iomem *v_regs;/* virtual address of p_regs */ 7062306a36Sopenharmony_ci u32 video; /* video flags before blanking */ 7162306a36Sopenharmony_ci u32 base; /* screen base in 128 bits unit */ 7262306a36Sopenharmony_ci u32 palette[16]; 7362306a36Sopenharmony_ci int wc_cookie; 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo 7862306a36Sopenharmony_ci * if we don't use modedb. If we do use modedb see pm3fb_init how to use it 7962306a36Sopenharmony_ci * to get a fb_var_screeninfo. Otherwise define a default var as well. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_cistatic struct fb_fix_screeninfo pm3fb_fix = { 8262306a36Sopenharmony_ci .id = "Permedia3", 8362306a36Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 8462306a36Sopenharmony_ci .visual = FB_VISUAL_PSEUDOCOLOR, 8562306a36Sopenharmony_ci .xpanstep = 1, 8662306a36Sopenharmony_ci .ypanstep = 1, 8762306a36Sopenharmony_ci .ywrapstep = 0, 8862306a36Sopenharmony_ci .accel = FB_ACCEL_3DLABS_PERMEDIA3, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * Utility functions 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline u32 PM3_READ_REG(struct pm3_par *par, s32 off) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci return fb_readl(par->v_regs + off); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci fb_writel(v, par->v_regs + off); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic inline void PM3_WAIT(struct pm3_par *par, u32 n) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci while (PM3_READ_REG(par, PM3InFIFOSpace) < n) 10862306a36Sopenharmony_ci cpu_relax(); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci PM3_WAIT(par, 3); 11462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff); 11562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff); 11662306a36Sopenharmony_ci wmb(); 11762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_IndexedData, v); 11862306a36Sopenharmony_ci wmb(); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno, 12262306a36Sopenharmony_ci unsigned char r, unsigned char g, unsigned char b) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci PM3_WAIT(par, 4); 12562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno); 12662306a36Sopenharmony_ci wmb(); 12762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_PaletteData, r); 12862306a36Sopenharmony_ci wmb(); 12962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_PaletteData, g); 13062306a36Sopenharmony_ci wmb(); 13162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RD_PaletteData, b); 13262306a36Sopenharmony_ci wmb(); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void pm3fb_clear_colormap(struct pm3_par *par, 13662306a36Sopenharmony_ci unsigned char r, unsigned char g, unsigned char b) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci int i; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci for (i = 0; i < 256 ; i++) 14162306a36Sopenharmony_ci pm3fb_set_color(par, i, r, g, b); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* Calculating various clock parameters */ 14662306a36Sopenharmony_cistatic void pm3fb_calculate_clock(unsigned long reqclock, 14762306a36Sopenharmony_ci unsigned char *prescale, 14862306a36Sopenharmony_ci unsigned char *feedback, 14962306a36Sopenharmony_ci unsigned char *postscale) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci int f, pre, post; 15262306a36Sopenharmony_ci unsigned long freq; 15362306a36Sopenharmony_ci long freqerr = 1000; 15462306a36Sopenharmony_ci long currerr; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci for (f = 1; f < 256; f++) { 15762306a36Sopenharmony_ci for (pre = 1; pre < 256; pre++) { 15862306a36Sopenharmony_ci for (post = 0; post < 5; post++) { 15962306a36Sopenharmony_ci freq = ((2*PM3_REF_CLOCK * f) >> post) / pre; 16062306a36Sopenharmony_ci currerr = (reqclock > freq) 16162306a36Sopenharmony_ci ? reqclock - freq 16262306a36Sopenharmony_ci : freq - reqclock; 16362306a36Sopenharmony_ci if (currerr < freqerr) { 16462306a36Sopenharmony_ci freqerr = currerr; 16562306a36Sopenharmony_ci *feedback = f; 16662306a36Sopenharmony_ci *prescale = pre; 16762306a36Sopenharmony_ci *postscale = post; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline int pm3fb_depth(const struct fb_var_screeninfo *var) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci if (var->bits_per_pixel == 16) 17762306a36Sopenharmony_ci return var->red.length + var->green.length 17862306a36Sopenharmony_ci + var->blue.length; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return var->bits_per_pixel; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic inline int pm3fb_shift_bpp(unsigned bpp, int v) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci switch (bpp) { 18662306a36Sopenharmony_ci case 8: 18762306a36Sopenharmony_ci return (v >> 4); 18862306a36Sopenharmony_ci case 16: 18962306a36Sopenharmony_ci return (v >> 3); 19062306a36Sopenharmony_ci case 32: 19162306a36Sopenharmony_ci return (v >> 2); 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci DPRINTK("Unsupported depth %u\n", bpp); 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* acceleration */ 19862306a36Sopenharmony_cistatic int pm3fb_sync(struct fb_info *info) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct pm3_par *par = info->par; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci PM3_WAIT(par, 2); 20362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); 20462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Sync, 0); 20562306a36Sopenharmony_ci mb(); 20662306a36Sopenharmony_ci do { 20762306a36Sopenharmony_ci while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0) 20862306a36Sopenharmony_ci cpu_relax(); 20962306a36Sopenharmony_ci } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void pm3fb_init_engine(struct fb_info *info) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct pm3_par *par = info->par; 21762306a36Sopenharmony_ci const u32 width = (info->var.xres_virtual + 7) & ~7; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci PM3_WAIT(par, 50); 22062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync); 22162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3StatisticMode, 0x0); 22262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3DeltaMode, 0x0); 22362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RasterizerMode, 0x0); 22462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMode, 0x0); 22562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3LineStippleMode, 0x0); 22662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0); 22762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3GIDMode, 0x0); 22862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3DepthMode, 0x0); 22962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3StencilMode, 0x0); 23062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3StencilData, 0x0); 23162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0); 23262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0); 23362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0); 23462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0); 23562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureReadMode, 0x0); 23662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3LUTMode, 0x0); 23762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0); 23862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0); 23962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0); 24062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0); 24162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0); 24262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0); 24362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0); 24462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FogMode, 0x0); 24562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0); 24662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0); 24762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3AntialiasMode, 0x0); 24862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3YUVMode, 0x0); 24962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0); 25062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0); 25162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3DitherMode, 0x0); 25262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0); 25362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RouterMode, 0x0); 25462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Window, 0x0); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Config2D, 0x0); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3XBias, 0x0); 26162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3YBias, 0x0); 26262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3DeltaControl, 0x0); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadEnables, 26762306a36Sopenharmony_ci PM3FBDestReadEnables_E(0xff) | 26862306a36Sopenharmony_ci PM3FBDestReadEnables_R(0xff) | 26962306a36Sopenharmony_ci PM3FBDestReadEnables_ReferenceAlpha(0xff)); 27062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0); 27162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0); 27262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0, 27362306a36Sopenharmony_ci PM3FBDestReadBufferWidth_Width(width)); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBDestReadMode, 27662306a36Sopenharmony_ci PM3FBDestReadMode_ReadEnable | 27762306a36Sopenharmony_ci PM3FBDestReadMode_Enable0); 27862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0); 27962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0); 28062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth, 28162306a36Sopenharmony_ci PM3FBSourceReadBufferWidth_Width(width)); 28262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadMode, 28362306a36Sopenharmony_ci PM3FBSourceReadMode_Blocking | 28462306a36Sopenharmony_ci PM3FBSourceReadMode_ReadEnable); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci PM3_WAIT(par, 2); 28762306a36Sopenharmony_ci { 28862306a36Sopenharmony_ci /* invert bits in bitmask */ 28962306a36Sopenharmony_ci unsigned long rm = 1 | (3 << 7); 29062306a36Sopenharmony_ci switch (info->var.bits_per_pixel) { 29162306a36Sopenharmony_ci case 8: 29262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3PixelSize, 29362306a36Sopenharmony_ci PM3PixelSize_GLOBAL_8BIT); 29462306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 29562306a36Sopenharmony_ci rm |= 3 << 15; 29662306a36Sopenharmony_ci#endif 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci case 16: 29962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3PixelSize, 30062306a36Sopenharmony_ci PM3PixelSize_GLOBAL_16BIT); 30162306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 30262306a36Sopenharmony_ci rm |= 2 << 15; 30362306a36Sopenharmony_ci#endif 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci case 32: 30662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3PixelSize, 30762306a36Sopenharmony_ci PM3PixelSize_GLOBAL_32BIT); 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci default: 31062306a36Sopenharmony_ci DPRINTK("Unsupported depth %d\n", 31162306a36Sopenharmony_ci info->var.bits_per_pixel); 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RasterizerMode, rm); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci PM3_WAIT(par, 20); 31862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff); 31962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff); 32062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBWriteMode, 32162306a36Sopenharmony_ci PM3FBWriteMode_WriteEnable | 32262306a36Sopenharmony_ci PM3FBWriteMode_OpaqueSpan | 32362306a36Sopenharmony_ci PM3FBWriteMode_Enable0); 32462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0); 32562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0); 32662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBWriteBufferWidth0, 32762306a36Sopenharmony_ci PM3FBWriteBufferWidth_Width(width)); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0); 33062306a36Sopenharmony_ci { 33162306a36Sopenharmony_ci /* size in lines of FB */ 33262306a36Sopenharmony_ci unsigned long sofb = info->screen_size / 33362306a36Sopenharmony_ci info->fix.line_length; 33462306a36Sopenharmony_ci if (sofb > 4095) 33562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095); 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci switch (info->var.bits_per_pixel) { 34062306a36Sopenharmony_ci case 8: 34162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3DitherMode, 34262306a36Sopenharmony_ci (1 << 10) | (2 << 3)); 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci case 16: 34562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3DitherMode, 34662306a36Sopenharmony_ci (1 << 10) | (1 << 3)); 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci case 32: 34962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3DitherMode, 35062306a36Sopenharmony_ci (1 << 10) | (0 << 3)); 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci default: 35362306a36Sopenharmony_ci DPRINTK("Unsupported depth %d\n", 35462306a36Sopenharmony_ci info->var.bits_per_pixel); 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3dXDom, 0x0); 36062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3dXSub, 0x0); 36162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3dY, 1 << 16); 36262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3StartXDom, 0x0); 36362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3StartXSub, 0x0); 36462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3StartY, 0x0); 36562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Count, 0x0); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* Disable LocalBuffer. better safe than sorry */ 36862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0); 36962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0); 37062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0); 37162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3LBWriteMode, 0x0); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci pm3fb_sync(info); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic void pm3fb_fillrect(struct fb_info *info, 37762306a36Sopenharmony_ci const struct fb_fillrect *region) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct pm3_par *par = info->par; 38062306a36Sopenharmony_ci struct fb_fillrect modded; 38162306a36Sopenharmony_ci int vxres, vyres; 38262306a36Sopenharmony_ci int rop; 38362306a36Sopenharmony_ci u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? 38462306a36Sopenharmony_ci ((u32 *)info->pseudo_palette)[region->color] : region->color; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 38762306a36Sopenharmony_ci return; 38862306a36Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 38962306a36Sopenharmony_ci cfb_fillrect(info, region); 39062306a36Sopenharmony_ci return; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci if (region->rop == ROP_COPY ) 39362306a36Sopenharmony_ci rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */ 39462306a36Sopenharmony_ci else 39562306a36Sopenharmony_ci rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */ 39662306a36Sopenharmony_ci PM3Config2D_FBDestReadEnable; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci vxres = info->var.xres_virtual; 39962306a36Sopenharmony_ci vyres = info->var.yres_virtual; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci memcpy(&modded, region, sizeof(struct fb_fillrect)); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (!modded.width || !modded.height || 40462306a36Sopenharmony_ci modded.dx >= vxres || modded.dy >= vyres) 40562306a36Sopenharmony_ci return; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (modded.dx + modded.width > vxres) 40862306a36Sopenharmony_ci modded.width = vxres - modded.dx; 40962306a36Sopenharmony_ci if (modded.dy + modded.height > vyres) 41062306a36Sopenharmony_ci modded.height = vyres - modded.dy; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (info->var.bits_per_pixel == 8) 41362306a36Sopenharmony_ci color |= color << 8; 41462306a36Sopenharmony_ci if (info->var.bits_per_pixel <= 16) 41562306a36Sopenharmony_ci color |= color << 16; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci PM3_WAIT(par, 4); 41862306a36Sopenharmony_ci /* ROP Ox3 is GXcopy */ 41962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Config2D, 42062306a36Sopenharmony_ci PM3Config2D_UseConstantSource | 42162306a36Sopenharmony_ci PM3Config2D_ForegroundROPEnable | 42262306a36Sopenharmony_ci rop | 42362306a36Sopenharmony_ci PM3Config2D_FBWriteEnable); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ForegroundColor, color); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RectanglePosition, 42862306a36Sopenharmony_ci PM3RectanglePosition_XOffset(modded.dx) | 42962306a36Sopenharmony_ci PM3RectanglePosition_YOffset(modded.dy)); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Render2D, 43262306a36Sopenharmony_ci PM3Render2D_XPositive | 43362306a36Sopenharmony_ci PM3Render2D_YPositive | 43462306a36Sopenharmony_ci PM3Render2D_Operation_Normal | 43562306a36Sopenharmony_ci PM3Render2D_SpanOperation | 43662306a36Sopenharmony_ci PM3Render2D_Width(modded.width) | 43762306a36Sopenharmony_ci PM3Render2D_Height(modded.height)); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void pm3fb_copyarea(struct fb_info *info, 44162306a36Sopenharmony_ci const struct fb_copyarea *area) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct pm3_par *par = info->par; 44462306a36Sopenharmony_ci struct fb_copyarea modded; 44562306a36Sopenharmony_ci u32 vxres, vyres; 44662306a36Sopenharmony_ci int x_align, o_x, o_y; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 44962306a36Sopenharmony_ci return; 45062306a36Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 45162306a36Sopenharmony_ci cfb_copyarea(info, area); 45262306a36Sopenharmony_ci return; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci memcpy(&modded, area, sizeof(struct fb_copyarea)); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci vxres = info->var.xres_virtual; 45862306a36Sopenharmony_ci vyres = info->var.yres_virtual; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (!modded.width || !modded.height || 46162306a36Sopenharmony_ci modded.sx >= vxres || modded.sy >= vyres || 46262306a36Sopenharmony_ci modded.dx >= vxres || modded.dy >= vyres) 46362306a36Sopenharmony_ci return; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (modded.sx + modded.width > vxres) 46662306a36Sopenharmony_ci modded.width = vxres - modded.sx; 46762306a36Sopenharmony_ci if (modded.dx + modded.width > vxres) 46862306a36Sopenharmony_ci modded.width = vxres - modded.dx; 46962306a36Sopenharmony_ci if (modded.sy + modded.height > vyres) 47062306a36Sopenharmony_ci modded.height = vyres - modded.sy; 47162306a36Sopenharmony_ci if (modded.dy + modded.height > vyres) 47262306a36Sopenharmony_ci modded.height = vyres - modded.dy; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci o_x = modded.sx - modded.dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ 47562306a36Sopenharmony_ci o_y = modded.sy - modded.dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci x_align = (modded.sx & 0x1f); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci PM3_WAIT(par, 6); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Config2D, 48262306a36Sopenharmony_ci PM3Config2D_UserScissorEnable | 48362306a36Sopenharmony_ci PM3Config2D_ForegroundROPEnable | 48462306a36Sopenharmony_ci PM3Config2D_Blocking | 48562306a36Sopenharmony_ci PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */ 48662306a36Sopenharmony_ci PM3Config2D_FBWriteEnable); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMinXY, 48962306a36Sopenharmony_ci ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff)); 49062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMaxXY, 49162306a36Sopenharmony_ci (((modded.dy + modded.height) & 0x0fff) << 16) | 49262306a36Sopenharmony_ci ((modded.dx + modded.width) & 0x0fff)); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 49562306a36Sopenharmony_ci PM3FBSourceReadBufferOffset_XOffset(o_x) | 49662306a36Sopenharmony_ci PM3FBSourceReadBufferOffset_YOffset(o_y)); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RectanglePosition, 49962306a36Sopenharmony_ci PM3RectanglePosition_XOffset(modded.dx - x_align) | 50062306a36Sopenharmony_ci PM3RectanglePosition_YOffset(modded.dy)); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Render2D, 50362306a36Sopenharmony_ci ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) | 50462306a36Sopenharmony_ci ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) | 50562306a36Sopenharmony_ci PM3Render2D_Operation_Normal | 50662306a36Sopenharmony_ci PM3Render2D_SpanOperation | 50762306a36Sopenharmony_ci PM3Render2D_FBSourceReadEnable | 50862306a36Sopenharmony_ci PM3Render2D_Width(modded.width + x_align) | 50962306a36Sopenharmony_ci PM3Render2D_Height(modded.height)); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct pm3_par *par = info->par; 51562306a36Sopenharmony_ci u32 height = image->height; 51662306a36Sopenharmony_ci u32 fgx, bgx; 51762306a36Sopenharmony_ci const u32 *src = (const u32 *)image->data; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (info->state != FBINFO_STATE_RUNNING) 52062306a36Sopenharmony_ci return; 52162306a36Sopenharmony_ci if (info->flags & FBINFO_HWACCEL_DISABLED) { 52262306a36Sopenharmony_ci cfb_imageblit(info, image); 52362306a36Sopenharmony_ci return; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci switch (info->fix.visual) { 52662306a36Sopenharmony_ci case FB_VISUAL_PSEUDOCOLOR: 52762306a36Sopenharmony_ci fgx = image->fg_color; 52862306a36Sopenharmony_ci bgx = image->bg_color; 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci case FB_VISUAL_TRUECOLOR: 53162306a36Sopenharmony_ci default: 53262306a36Sopenharmony_ci fgx = par->palette[image->fg_color]; 53362306a36Sopenharmony_ci bgx = par->palette[image->bg_color]; 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci if (image->depth != 1) { 53762306a36Sopenharmony_ci cfb_imageblit(info, image); 53862306a36Sopenharmony_ci return; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (info->var.bits_per_pixel == 8) { 54262306a36Sopenharmony_ci fgx |= fgx << 8; 54362306a36Sopenharmony_ci bgx |= bgx << 8; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci if (info->var.bits_per_pixel <= 16) { 54662306a36Sopenharmony_ci fgx |= fgx << 16; 54762306a36Sopenharmony_ci bgx |= bgx << 16; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci PM3_WAIT(par, 7); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ForegroundColor, fgx); 55362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3BackgroundColor, bgx); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* ROP Ox3 is GXcopy */ 55662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Config2D, 55762306a36Sopenharmony_ci PM3Config2D_UserScissorEnable | 55862306a36Sopenharmony_ci PM3Config2D_UseConstantSource | 55962306a36Sopenharmony_ci PM3Config2D_ForegroundROPEnable | 56062306a36Sopenharmony_ci PM3Config2D_ForegroundROP(0x3) | 56162306a36Sopenharmony_ci PM3Config2D_OpaqueSpan | 56262306a36Sopenharmony_ci PM3Config2D_FBWriteEnable); 56362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMinXY, 56462306a36Sopenharmony_ci ((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff)); 56562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ScissorMaxXY, 56662306a36Sopenharmony_ci (((image->dy + image->height) & 0x0fff) << 16) | 56762306a36Sopenharmony_ci ((image->dx + image->width) & 0x0fff)); 56862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3RectanglePosition, 56962306a36Sopenharmony_ci PM3RectanglePosition_XOffset(image->dx) | 57062306a36Sopenharmony_ci PM3RectanglePosition_YOffset(image->dy)); 57162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Render2D, 57262306a36Sopenharmony_ci PM3Render2D_XPositive | 57362306a36Sopenharmony_ci PM3Render2D_YPositive | 57462306a36Sopenharmony_ci PM3Render2D_Operation_SyncOnBitMask | 57562306a36Sopenharmony_ci PM3Render2D_SpanOperation | 57662306a36Sopenharmony_ci PM3Render2D_Width(image->width) | 57762306a36Sopenharmony_ci PM3Render2D_Height(image->height)); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci while (height--) { 58162306a36Sopenharmony_ci int width = ((image->width + 7) >> 3) 58262306a36Sopenharmony_ci + info->pixmap.scan_align - 1; 58362306a36Sopenharmony_ci width >>= 2; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci while (width >= PM3_FIFO_SIZE) { 58662306a36Sopenharmony_ci int i = PM3_FIFO_SIZE - 1; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci PM3_WAIT(par, PM3_FIFO_SIZE); 58962306a36Sopenharmony_ci while (i--) { 59062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3BitMaskPattern, *src); 59162306a36Sopenharmony_ci src++; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci width -= PM3_FIFO_SIZE - 1; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci PM3_WAIT(par, width + 1); 59762306a36Sopenharmony_ci while (width--) { 59862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3BitMaskPattern, *src); 59962306a36Sopenharmony_ci src++; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci/* end of acceleration functions */ 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci/* 60662306a36Sopenharmony_ci * Hardware Cursor support. 60762306a36Sopenharmony_ci */ 60862306a36Sopenharmony_cistatic const u8 cursor_bits_lookup[16] = { 60962306a36Sopenharmony_ci 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 61062306a36Sopenharmony_ci 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55 61162306a36Sopenharmony_ci}; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic int pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct pm3_par *par = info->par; 61662306a36Sopenharmony_ci u8 mode; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (!hwcursor) 61962306a36Sopenharmony_ci return -EINVAL; /* just to force soft_cursor() call */ 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* Too large of a cursor or wrong bpp :-( */ 62262306a36Sopenharmony_ci if (cursor->image.width > 64 || 62362306a36Sopenharmony_ci cursor->image.height > 64 || 62462306a36Sopenharmony_ci cursor->image.depth > 1) 62562306a36Sopenharmony_ci return -EINVAL; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci mode = PM3RD_CursorMode_TYPE_X; 62862306a36Sopenharmony_ci if (cursor->enable) 62962306a36Sopenharmony_ci mode |= PM3RD_CursorMode_CURSOR_ENABLE; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* 63462306a36Sopenharmony_ci * If the cursor is not be changed this means either we want the 63562306a36Sopenharmony_ci * current cursor state (if enable is set) or we want to query what 63662306a36Sopenharmony_ci * we can do with the cursor (if enable is not set) 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_ci if (!cursor->set) 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETPOS) { 64262306a36Sopenharmony_ci int x = cursor->image.dx - info->var.xoffset; 64362306a36Sopenharmony_ci int y = cursor->image.dy - info->var.yoffset; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff); 64662306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf); 64762306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff); 64862306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETHOT) { 65262306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX, 65362306a36Sopenharmony_ci cursor->hot.x & 0x3f); 65462306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY, 65562306a36Sopenharmony_ci cursor->hot.y & 0x3f); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci if (cursor->set & FB_CUR_SETCMAP) { 65962306a36Sopenharmony_ci u32 fg_idx = cursor->image.fg_color; 66062306a36Sopenharmony_ci u32 bg_idx = cursor->image.bg_color; 66162306a36Sopenharmony_ci struct fb_cmap cmap = info->cmap; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* the X11 driver says one should use these color registers */ 66462306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39), 66562306a36Sopenharmony_ci cmap.red[fg_idx] >> 8 ); 66662306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40), 66762306a36Sopenharmony_ci cmap.green[fg_idx] >> 8 ); 66862306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41), 66962306a36Sopenharmony_ci cmap.blue[fg_idx] >> 8 ); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42), 67262306a36Sopenharmony_ci cmap.red[bg_idx] >> 8 ); 67362306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43), 67462306a36Sopenharmony_ci cmap.green[bg_idx] >> 8 ); 67562306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44), 67662306a36Sopenharmony_ci cmap.blue[bg_idx] >> 8 ); 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { 68062306a36Sopenharmony_ci u8 *bitmap = (u8 *)cursor->image.data; 68162306a36Sopenharmony_ci u8 *mask = (u8 *)cursor->mask; 68262306a36Sopenharmony_ci int i; 68362306a36Sopenharmony_ci int pos = PM3RD_CursorPattern(0); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci for (i = 0; i < cursor->image.height; i++) { 68662306a36Sopenharmony_ci int j = (cursor->image.width + 7) >> 3; 68762306a36Sopenharmony_ci int k = 8 - j; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci for (; j > 0; j--) { 69062306a36Sopenharmony_ci u8 data = *bitmap ^ *mask; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (cursor->rop == ROP_COPY) 69362306a36Sopenharmony_ci data = *mask & *bitmap; 69462306a36Sopenharmony_ci /* Upper 4 bits of bitmap data */ 69562306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 69662306a36Sopenharmony_ci cursor_bits_lookup[data >> 4] | 69762306a36Sopenharmony_ci (cursor_bits_lookup[*mask >> 4] << 1)); 69862306a36Sopenharmony_ci /* Lower 4 bits of bitmap */ 69962306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 70062306a36Sopenharmony_ci cursor_bits_lookup[data & 0xf] | 70162306a36Sopenharmony_ci (cursor_bits_lookup[*mask & 0xf] << 1)); 70262306a36Sopenharmony_ci bitmap++; 70362306a36Sopenharmony_ci mask++; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci for (; k > 0; k--) { 70662306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 0); 70762306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 0); 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci while (pos < PM3RD_CursorPattern(1024)) 71162306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, pos++, 0); 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci return 0; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci/* write the mode to registers */ 71762306a36Sopenharmony_cistatic void pm3fb_write_mode(struct fb_info *info) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct pm3_par *par = info->par; 72062306a36Sopenharmony_ci char tempsync = 0x00; 72162306a36Sopenharmony_ci char tempmisc = 0x00; 72262306a36Sopenharmony_ci const u32 hsstart = info->var.right_margin; 72362306a36Sopenharmony_ci const u32 hsend = hsstart + info->var.hsync_len; 72462306a36Sopenharmony_ci const u32 hbend = hsend + info->var.left_margin; 72562306a36Sopenharmony_ci const u32 xres = (info->var.xres + 31) & ~31; 72662306a36Sopenharmony_ci const u32 htotal = xres + hbend; 72762306a36Sopenharmony_ci const u32 vsstart = info->var.lower_margin; 72862306a36Sopenharmony_ci const u32 vsend = vsstart + info->var.vsync_len; 72962306a36Sopenharmony_ci const u32 vbend = vsend + info->var.upper_margin; 73062306a36Sopenharmony_ci const u32 vtotal = info->var.yres + vbend; 73162306a36Sopenharmony_ci const u32 width = (info->var.xres_virtual + 7) & ~7; 73262306a36Sopenharmony_ci const unsigned bpp = info->var.bits_per_pixel; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci PM3_WAIT(par, 20); 73562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff); 73662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Aperture0, 0x00000000); 73762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3Aperture1, 0x00000000); 73862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3FIFODis, 0x00000007); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3HTotal, 74162306a36Sopenharmony_ci pm3fb_shift_bpp(bpp, htotal - 1)); 74262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3HsEnd, 74362306a36Sopenharmony_ci pm3fb_shift_bpp(bpp, hsend)); 74462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3HsStart, 74562306a36Sopenharmony_ci pm3fb_shift_bpp(bpp, hsstart)); 74662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3HbEnd, 74762306a36Sopenharmony_ci pm3fb_shift_bpp(bpp, hbend)); 74862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3HgEnd, 74962306a36Sopenharmony_ci pm3fb_shift_bpp(bpp, hbend)); 75062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ScreenStride, 75162306a36Sopenharmony_ci pm3fb_shift_bpp(bpp, width)); 75262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3VTotal, vtotal - 1); 75362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3VsEnd, vsend - 1); 75462306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3VsStart, vsstart - 1); 75562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3VbEnd, vbend); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci switch (bpp) { 75862306a36Sopenharmony_ci case 8: 75962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 76062306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_8BIT); 76162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 76262306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_8BIT); 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci case 16: 76662306a36Sopenharmony_ci#ifndef __BIG_ENDIAN 76762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 76862306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_16BIT); 76962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 77062306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_16BIT); 77162306a36Sopenharmony_ci#else 77262306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 77362306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_16BIT | 77462306a36Sopenharmony_ci PM3ByApertureMode_BYTESWAP_BADC); 77562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 77662306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_16BIT | 77762306a36Sopenharmony_ci PM3ByApertureMode_BYTESWAP_BADC); 77862306a36Sopenharmony_ci#endif /* ! __BIG_ENDIAN */ 77962306a36Sopenharmony_ci break; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci case 32: 78262306a36Sopenharmony_ci#ifndef __BIG_ENDIAN 78362306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 78462306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_32BIT); 78562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 78662306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_32BIT); 78762306a36Sopenharmony_ci#else 78862306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture1Mode, 78962306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_32BIT | 79062306a36Sopenharmony_ci PM3ByApertureMode_BYTESWAP_DCBA); 79162306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ByAperture2Mode, 79262306a36Sopenharmony_ci PM3ByApertureMode_PIXELSIZE_32BIT | 79362306a36Sopenharmony_ci PM3ByApertureMode_BYTESWAP_DCBA); 79462306a36Sopenharmony_ci#endif /* ! __BIG_ENDIAN */ 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci default: 79862306a36Sopenharmony_ci DPRINTK("Unsupported depth %d\n", bpp); 79962306a36Sopenharmony_ci break; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* 80362306a36Sopenharmony_ci * Oxygen VX1 - it appears that setting PM3VideoControl and 80462306a36Sopenharmony_ci * then PM3RD_SyncControl to the same SYNC settings undoes 80562306a36Sopenharmony_ci * any net change - they seem to xor together. Only set the 80662306a36Sopenharmony_ci * sync options in PM3RD_SyncControl. --rmk 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_ci { 80962306a36Sopenharmony_ci unsigned int video = par->video; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci video &= ~(PM3VideoControl_HSYNC_MASK | 81262306a36Sopenharmony_ci PM3VideoControl_VSYNC_MASK); 81362306a36Sopenharmony_ci video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 81462306a36Sopenharmony_ci PM3VideoControl_VSYNC_ACTIVE_HIGH; 81562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3VideoControl, video); 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3VClkCtl, 81862306a36Sopenharmony_ci (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC)); 81962306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ScreenBase, par->base); 82062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ChipConfig, 82162306a36Sopenharmony_ci (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD)); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci wmb(); 82462306a36Sopenharmony_ci { 82562306a36Sopenharmony_ci unsigned char m; /* ClkPreScale */ 82662306a36Sopenharmony_ci unsigned char n; /* ClkFeedBackScale */ 82762306a36Sopenharmony_ci unsigned char p; /* ClkPostScale */ 82862306a36Sopenharmony_ci unsigned long pixclock = PICOS2KHZ(info->var.pixclock); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci (void)pm3fb_calculate_clock(pixclock, &m, &n, &p); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n", 83362306a36Sopenharmony_ci pixclock, (int) m, (int) n, (int) p); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m); 83662306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n); 83762306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci /* 84062306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00); 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci /* 84362306a36Sopenharmony_ci PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00); 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ci if ((par->video & PM3VideoControl_HSYNC_MASK) == 84662306a36Sopenharmony_ci PM3VideoControl_HSYNC_ACTIVE_HIGH) 84762306a36Sopenharmony_ci tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; 84862306a36Sopenharmony_ci if ((par->video & PM3VideoControl_VSYNC_MASK) == 84962306a36Sopenharmony_ci PM3VideoControl_VSYNC_ACTIVE_HIGH) 85062306a36Sopenharmony_ci tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync); 85362306a36Sopenharmony_ci DPRINTK("PM3RD_SyncControl: %d\n", tempsync); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci switch (pm3fb_depth(&info->var)) { 85862306a36Sopenharmony_ci case 8: 85962306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 86062306a36Sopenharmony_ci PM3RD_PixelSize_8_BIT_PIXELS); 86162306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 86262306a36Sopenharmony_ci PM3RD_ColorFormat_CI8_COLOR | 86362306a36Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 86462306a36Sopenharmony_ci tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci case 12: 86762306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 86862306a36Sopenharmony_ci PM3RD_PixelSize_16_BIT_PIXELS); 86962306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 87062306a36Sopenharmony_ci PM3RD_ColorFormat_4444_COLOR | 87162306a36Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 87262306a36Sopenharmony_ci PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 87362306a36Sopenharmony_ci tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 87462306a36Sopenharmony_ci PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 87562306a36Sopenharmony_ci break; 87662306a36Sopenharmony_ci case 15: 87762306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 87862306a36Sopenharmony_ci PM3RD_PixelSize_16_BIT_PIXELS); 87962306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 88062306a36Sopenharmony_ci PM3RD_ColorFormat_5551_FRONT_COLOR | 88162306a36Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 88262306a36Sopenharmony_ci PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 88362306a36Sopenharmony_ci tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 88462306a36Sopenharmony_ci PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 88562306a36Sopenharmony_ci break; 88662306a36Sopenharmony_ci case 16: 88762306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 88862306a36Sopenharmony_ci PM3RD_PixelSize_16_BIT_PIXELS); 88962306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 89062306a36Sopenharmony_ci PM3RD_ColorFormat_565_FRONT_COLOR | 89162306a36Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | 89262306a36Sopenharmony_ci PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); 89362306a36Sopenharmony_ci tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 89462306a36Sopenharmony_ci PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 89562306a36Sopenharmony_ci break; 89662306a36Sopenharmony_ci case 32: 89762306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, 89862306a36Sopenharmony_ci PM3RD_PixelSize_32_BIT_PIXELS); 89962306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, 90062306a36Sopenharmony_ci PM3RD_ColorFormat_8888_COLOR | 90162306a36Sopenharmony_ci PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); 90262306a36Sopenharmony_ci tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | 90362306a36Sopenharmony_ci PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; 90462306a36Sopenharmony_ci break; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci/* 91062306a36Sopenharmony_ci * hardware independent functions 91162306a36Sopenharmony_ci */ 91262306a36Sopenharmony_cistatic int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci u32 lpitch; 91562306a36Sopenharmony_ci unsigned bpp = var->red.length + var->green.length 91662306a36Sopenharmony_ci + var->blue.length + var->transp.length; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (bpp != var->bits_per_pixel) { 91962306a36Sopenharmony_ci /* set predefined mode for bits_per_pixel settings */ 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci switch (var->bits_per_pixel) { 92262306a36Sopenharmony_ci case 8: 92362306a36Sopenharmony_ci var->red.length = 8; 92462306a36Sopenharmony_ci var->green.length = 8; 92562306a36Sopenharmony_ci var->blue.length = 8; 92662306a36Sopenharmony_ci var->red.offset = 0; 92762306a36Sopenharmony_ci var->green.offset = 0; 92862306a36Sopenharmony_ci var->blue.offset = 0; 92962306a36Sopenharmony_ci var->transp.offset = 0; 93062306a36Sopenharmony_ci var->transp.length = 0; 93162306a36Sopenharmony_ci break; 93262306a36Sopenharmony_ci case 16: 93362306a36Sopenharmony_ci var->red.length = 5; 93462306a36Sopenharmony_ci var->blue.length = 5; 93562306a36Sopenharmony_ci var->green.length = 6; 93662306a36Sopenharmony_ci var->transp.length = 0; 93762306a36Sopenharmony_ci break; 93862306a36Sopenharmony_ci case 32: 93962306a36Sopenharmony_ci var->red.length = 8; 94062306a36Sopenharmony_ci var->green.length = 8; 94162306a36Sopenharmony_ci var->blue.length = 8; 94262306a36Sopenharmony_ci var->transp.length = 8; 94362306a36Sopenharmony_ci break; 94462306a36Sopenharmony_ci default: 94562306a36Sopenharmony_ci DPRINTK("depth not supported: %u\n", 94662306a36Sopenharmony_ci var->bits_per_pixel); 94762306a36Sopenharmony_ci return -EINVAL; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci /* it is assumed BGRA order */ 95162306a36Sopenharmony_ci if (var->bits_per_pixel > 8 ) { 95262306a36Sopenharmony_ci var->blue.offset = 0; 95362306a36Sopenharmony_ci var->green.offset = var->blue.length; 95462306a36Sopenharmony_ci var->red.offset = var->green.offset + var->green.length; 95562306a36Sopenharmony_ci var->transp.offset = var->red.offset + var->red.length; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci var->height = -1; 95862306a36Sopenharmony_ci var->width = -1; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (var->xres != var->xres_virtual) { 96162306a36Sopenharmony_ci DPRINTK("virtual x resolution != " 96262306a36Sopenharmony_ci "physical x resolution not supported\n"); 96362306a36Sopenharmony_ci return -EINVAL; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (var->yres > var->yres_virtual) { 96762306a36Sopenharmony_ci DPRINTK("virtual y resolution < " 96862306a36Sopenharmony_ci "physical y resolution not possible\n"); 96962306a36Sopenharmony_ci return -EINVAL; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (var->xoffset) { 97362306a36Sopenharmony_ci DPRINTK("xoffset not supported\n"); 97462306a36Sopenharmony_ci return -EINVAL; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 97862306a36Sopenharmony_ci DPRINTK("interlace not supported\n"); 97962306a36Sopenharmony_ci return -EINVAL; 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ 98362306a36Sopenharmony_ci lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (var->xres < 200 || var->xres > 2048) { 98662306a36Sopenharmony_ci DPRINTK("width not supported: %u\n", var->xres); 98762306a36Sopenharmony_ci return -EINVAL; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (var->yres < 200 || var->yres > 4095) { 99162306a36Sopenharmony_ci DPRINTK("height not supported: %u\n", var->yres); 99262306a36Sopenharmony_ci return -EINVAL; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci if (lpitch * var->yres_virtual > info->fix.smem_len) { 99662306a36Sopenharmony_ci DPRINTK("no memory for screen (%ux%ux%u)\n", 99762306a36Sopenharmony_ci var->xres, var->yres_virtual, var->bits_per_pixel); 99862306a36Sopenharmony_ci return -EINVAL; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { 100262306a36Sopenharmony_ci DPRINTK("pixclock too high (%ldKHz)\n", 100362306a36Sopenharmony_ci PICOS2KHZ(var->pixclock)); 100462306a36Sopenharmony_ci return -EINVAL; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci var->accel_flags = 0; /* Can't mmap if this is on */ 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci DPRINTK("Checking graphics mode at %dx%d depth %d\n", 101062306a36Sopenharmony_ci var->xres, var->yres, var->bits_per_pixel); 101162306a36Sopenharmony_ci return 0; 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic int pm3fb_set_par(struct fb_info *info) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct pm3_par *par = info->par; 101762306a36Sopenharmony_ci const u32 xres = (info->var.xres + 31) & ~31; 101862306a36Sopenharmony_ci const unsigned bpp = info->var.bits_per_pixel; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres) 102162306a36Sopenharmony_ci + info->var.xoffset); 102262306a36Sopenharmony_ci par->video = 0; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 102562306a36Sopenharmony_ci par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; 102662306a36Sopenharmony_ci else 102762306a36Sopenharmony_ci par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 103062306a36Sopenharmony_ci par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; 103162306a36Sopenharmony_ci else 103262306a36Sopenharmony_ci par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) 103562306a36Sopenharmony_ci par->video |= PM3VideoControl_LINE_DOUBLE_ON; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) 103862306a36Sopenharmony_ci par->video |= PM3VideoControl_ENABLE; 103962306a36Sopenharmony_ci else 104062306a36Sopenharmony_ci DPRINTK("PM3Video disabled\n"); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci switch (bpp) { 104362306a36Sopenharmony_ci case 8: 104462306a36Sopenharmony_ci par->video |= PM3VideoControl_PIXELSIZE_8BIT; 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci case 16: 104762306a36Sopenharmony_ci par->video |= PM3VideoControl_PIXELSIZE_16BIT; 104862306a36Sopenharmony_ci break; 104962306a36Sopenharmony_ci case 32: 105062306a36Sopenharmony_ci par->video |= PM3VideoControl_PIXELSIZE_32BIT; 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci default: 105362306a36Sopenharmony_ci DPRINTK("Unsupported depth\n"); 105462306a36Sopenharmony_ci break; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci info->fix.visual = 105862306a36Sopenharmony_ci (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 105962306a36Sopenharmony_ci info->fix.line_length = ((info->var.xres_virtual + 7) >> 3) * bpp; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci/* pm3fb_clear_memory(info, 0);*/ 106262306a36Sopenharmony_ci pm3fb_clear_colormap(par, 0, 0, 0); 106362306a36Sopenharmony_ci PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0); 106462306a36Sopenharmony_ci pm3fb_init_engine(info); 106562306a36Sopenharmony_ci pm3fb_write_mode(info); 106662306a36Sopenharmony_ci return 0; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, 107062306a36Sopenharmony_ci unsigned blue, unsigned transp, 107162306a36Sopenharmony_ci struct fb_info *info) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci struct pm3_par *par = info->par; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (regno >= 256) /* no. of hw registers */ 107662306a36Sopenharmony_ci return -EINVAL; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* grayscale works only partially under directcolor */ 107962306a36Sopenharmony_ci /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 108062306a36Sopenharmony_ci if (info->var.grayscale) 108162306a36Sopenharmony_ci red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* Directcolor: 108462306a36Sopenharmony_ci * var->{color}.offset contains start of bitfield 108562306a36Sopenharmony_ci * var->{color}.length contains length of bitfield 108662306a36Sopenharmony_ci * {hardwarespecific} contains width of DAC 108762306a36Sopenharmony_ci * pseudo_palette[X] is programmed to (X << red.offset) | 108862306a36Sopenharmony_ci * (X << green.offset) | 108962306a36Sopenharmony_ci * (X << blue.offset) 109062306a36Sopenharmony_ci * RAMDAC[X] is programmed to (red, green, blue) 109162306a36Sopenharmony_ci * color depth = SUM(var->{color}.length) 109262306a36Sopenharmony_ci * 109362306a36Sopenharmony_ci * Pseudocolor: 109462306a36Sopenharmony_ci * var->{color}.offset is 0 109562306a36Sopenharmony_ci * var->{color}.length contains width of DAC or the number 109662306a36Sopenharmony_ci * of unique colors available (color depth) 109762306a36Sopenharmony_ci * pseudo_palette is not used 109862306a36Sopenharmony_ci * RAMDAC[X] is programmed to (red, green, blue) 109962306a36Sopenharmony_ci * color depth = var->{color}.length 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci /* 110362306a36Sopenharmony_ci * This is the point where the color is converted to something that 110462306a36Sopenharmony_ci * is acceptable by the hardware. 110562306a36Sopenharmony_ci */ 110662306a36Sopenharmony_ci#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) 110762306a36Sopenharmony_ci red = CNVT_TOHW(red, info->var.red.length); 110862306a36Sopenharmony_ci green = CNVT_TOHW(green, info->var.green.length); 110962306a36Sopenharmony_ci blue = CNVT_TOHW(blue, info->var.blue.length); 111062306a36Sopenharmony_ci transp = CNVT_TOHW(transp, info->var.transp.length); 111162306a36Sopenharmony_ci#undef CNVT_TOHW 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (info->fix.visual == FB_VISUAL_TRUECOLOR || 111462306a36Sopenharmony_ci info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 111562306a36Sopenharmony_ci u32 v; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (regno >= 16) 111862306a36Sopenharmony_ci return -EINVAL; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci v = (red << info->var.red.offset) | 112162306a36Sopenharmony_ci (green << info->var.green.offset) | 112262306a36Sopenharmony_ci (blue << info->var.blue.offset) | 112362306a36Sopenharmony_ci (transp << info->var.transp.offset); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci switch (info->var.bits_per_pixel) { 112662306a36Sopenharmony_ci case 8: 112762306a36Sopenharmony_ci break; 112862306a36Sopenharmony_ci case 16: 112962306a36Sopenharmony_ci case 32: 113062306a36Sopenharmony_ci ((u32 *)(info->pseudo_palette))[regno] = v; 113162306a36Sopenharmony_ci break; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) 113562306a36Sopenharmony_ci pm3fb_set_color(par, regno, red, green, blue); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci return 0; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic int pm3fb_pan_display(struct fb_var_screeninfo *var, 114162306a36Sopenharmony_ci struct fb_info *info) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct pm3_par *par = info->par; 114462306a36Sopenharmony_ci const u32 xres = (info->var.xres + 31) & ~31; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci par->base = pm3fb_shift_bpp(info->var.bits_per_pixel, 114762306a36Sopenharmony_ci (var->yoffset * xres) 114862306a36Sopenharmony_ci + var->xoffset); 114962306a36Sopenharmony_ci PM3_WAIT(par, 1); 115062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3ScreenBase, par->base); 115162306a36Sopenharmony_ci return 0; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic int pm3fb_blank(int blank_mode, struct fb_info *info) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci struct pm3_par *par = info->par; 115762306a36Sopenharmony_ci u32 video = par->video; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* 116062306a36Sopenharmony_ci * Oxygen VX1 - it appears that setting PM3VideoControl and 116162306a36Sopenharmony_ci * then PM3RD_SyncControl to the same SYNC settings undoes 116262306a36Sopenharmony_ci * any net change - they seem to xor together. Only set the 116362306a36Sopenharmony_ci * sync options in PM3RD_SyncControl. --rmk 116462306a36Sopenharmony_ci */ 116562306a36Sopenharmony_ci video &= ~(PM3VideoControl_HSYNC_MASK | 116662306a36Sopenharmony_ci PM3VideoControl_VSYNC_MASK); 116762306a36Sopenharmony_ci video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | 116862306a36Sopenharmony_ci PM3VideoControl_VSYNC_ACTIVE_HIGH; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci switch (blank_mode) { 117162306a36Sopenharmony_ci case FB_BLANK_UNBLANK: 117262306a36Sopenharmony_ci video |= PM3VideoControl_ENABLE; 117362306a36Sopenharmony_ci break; 117462306a36Sopenharmony_ci case FB_BLANK_NORMAL: 117562306a36Sopenharmony_ci video &= ~PM3VideoControl_ENABLE; 117662306a36Sopenharmony_ci break; 117762306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 117862306a36Sopenharmony_ci video &= ~(PM3VideoControl_HSYNC_MASK | 117962306a36Sopenharmony_ci PM3VideoControl_BLANK_ACTIVE_LOW); 118062306a36Sopenharmony_ci break; 118162306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 118262306a36Sopenharmony_ci video &= ~(PM3VideoControl_VSYNC_MASK | 118362306a36Sopenharmony_ci PM3VideoControl_BLANK_ACTIVE_LOW); 118462306a36Sopenharmony_ci break; 118562306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: 118662306a36Sopenharmony_ci video &= ~(PM3VideoControl_HSYNC_MASK | 118762306a36Sopenharmony_ci PM3VideoControl_VSYNC_MASK | 118862306a36Sopenharmony_ci PM3VideoControl_BLANK_ACTIVE_LOW); 118962306a36Sopenharmony_ci break; 119062306a36Sopenharmony_ci default: 119162306a36Sopenharmony_ci DPRINTK("Unsupported blanking %d\n", blank_mode); 119262306a36Sopenharmony_ci return 1; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci PM3_WAIT(par, 1); 119662306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3VideoControl, video); 119762306a36Sopenharmony_ci return 0; 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* 120162306a36Sopenharmony_ci * Frame buffer operations 120262306a36Sopenharmony_ci */ 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_cistatic const struct fb_ops pm3fb_ops = { 120562306a36Sopenharmony_ci .owner = THIS_MODULE, 120662306a36Sopenharmony_ci .fb_check_var = pm3fb_check_var, 120762306a36Sopenharmony_ci .fb_set_par = pm3fb_set_par, 120862306a36Sopenharmony_ci .fb_setcolreg = pm3fb_setcolreg, 120962306a36Sopenharmony_ci .fb_pan_display = pm3fb_pan_display, 121062306a36Sopenharmony_ci .fb_fillrect = pm3fb_fillrect, 121162306a36Sopenharmony_ci .fb_copyarea = pm3fb_copyarea, 121262306a36Sopenharmony_ci .fb_imageblit = pm3fb_imageblit, 121362306a36Sopenharmony_ci .fb_blank = pm3fb_blank, 121462306a36Sopenharmony_ci .fb_sync = pm3fb_sync, 121562306a36Sopenharmony_ci .fb_cursor = pm3fb_cursor, 121662306a36Sopenharmony_ci}; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci/* ------------------------------------------------------------------------- */ 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* 122162306a36Sopenharmony_ci * Initialization 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci/* mmio register are already mapped when this function is called */ 122562306a36Sopenharmony_ci/* the pm3fb_fix.smem_start is also set */ 122662306a36Sopenharmony_cistatic unsigned long pm3fb_size_memory(struct pm3_par *par) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci unsigned long memsize = 0; 122962306a36Sopenharmony_ci unsigned long tempBypass, i, temp1, temp2; 123062306a36Sopenharmony_ci unsigned char __iomem *screen_mem; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */ 123362306a36Sopenharmony_ci /* Linear frame buffer - request region and map it. */ 123462306a36Sopenharmony_ci if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 123562306a36Sopenharmony_ci "pm3fb smem")) { 123662306a36Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 123762306a36Sopenharmony_ci return 0; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci screen_mem = 124062306a36Sopenharmony_ci ioremap(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 124162306a36Sopenharmony_ci if (!screen_mem) { 124262306a36Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 124362306a36Sopenharmony_ci release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 124462306a36Sopenharmony_ci return 0; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci /* TODO: card-specific stuff, *before* accessing *any* FB memory */ 124862306a36Sopenharmony_ci /* For Appian Jeronimo 2000 board second head */ 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci PM3_WAIT(par, 1); 125562306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* pm3 split up memory, replicates, and do a lot of 125862306a36Sopenharmony_ci * nasty stuff IMHO ;-) 125962306a36Sopenharmony_ci */ 126062306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 126162306a36Sopenharmony_ci fb_writel(i * 0x00345678, 126262306a36Sopenharmony_ci (screen_mem + (i * 1048576))); 126362306a36Sopenharmony_ci mb(); 126462306a36Sopenharmony_ci temp1 = fb_readl((screen_mem + (i * 1048576))); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* Let's check for wrapover, write will fail at 16MB boundary */ 126762306a36Sopenharmony_ci if (temp1 == (i * 0x00345678)) 126862306a36Sopenharmony_ci memsize = i; 126962306a36Sopenharmony_ci else 127062306a36Sopenharmony_ci break; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci DPRINTK("First detect pass already got %ld MB\n", memsize + 1); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci if (memsize + 1 == i) { 127662306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 127762306a36Sopenharmony_ci /* Clear first 32MB ; 0 is 0, no need to byteswap */ 127862306a36Sopenharmony_ci writel(0x0000000, (screen_mem + (i * 1048576))); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci wmb(); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci for (i = 32; i < 64; i++) { 128362306a36Sopenharmony_ci fb_writel(i * 0x00345678, 128462306a36Sopenharmony_ci (screen_mem + (i * 1048576))); 128562306a36Sopenharmony_ci mb(); 128662306a36Sopenharmony_ci temp1 = 128762306a36Sopenharmony_ci fb_readl((screen_mem + (i * 1048576))); 128862306a36Sopenharmony_ci temp2 = 128962306a36Sopenharmony_ci fb_readl((screen_mem + ((i - 32) * 1048576))); 129062306a36Sopenharmony_ci /* different value, different RAM... */ 129162306a36Sopenharmony_ci if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) 129262306a36Sopenharmony_ci memsize = i; 129362306a36Sopenharmony_ci else 129462306a36Sopenharmony_ci break; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci DPRINTK("Second detect pass got %ld MB\n", memsize + 1); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci PM3_WAIT(par, 1); 130062306a36Sopenharmony_ci PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci iounmap(screen_mem); 130362306a36Sopenharmony_ci release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 130462306a36Sopenharmony_ci memsize = 1048576 * (memsize + 1); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci DPRINTK("Returning 0x%08lx bytes\n", memsize); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return memsize; 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic int pm3fb_probe(struct pci_dev *dev, const struct pci_device_id *ent) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct fb_info *info; 131462306a36Sopenharmony_ci struct pm3_par *par; 131562306a36Sopenharmony_ci struct device *device = &dev->dev; /* for pci drivers */ 131662306a36Sopenharmony_ci int err; 131762306a36Sopenharmony_ci int retval = -ENXIO; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci err = aperture_remove_conflicting_pci_devices(dev, "pm3fb"); 132062306a36Sopenharmony_ci if (err) 132162306a36Sopenharmony_ci return err; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci err = pci_enable_device(dev); 132462306a36Sopenharmony_ci if (err) { 132562306a36Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); 132662306a36Sopenharmony_ci return err; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci /* 132962306a36Sopenharmony_ci * Dynamically allocate info and par 133062306a36Sopenharmony_ci */ 133162306a36Sopenharmony_ci info = framebuffer_alloc(sizeof(struct pm3_par), device); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (!info) 133462306a36Sopenharmony_ci return -ENOMEM; 133562306a36Sopenharmony_ci par = info->par; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci /* 133862306a36Sopenharmony_ci * Here we set the screen_base to the virtual memory address 133962306a36Sopenharmony_ci * for the framebuffer. 134062306a36Sopenharmony_ci */ 134162306a36Sopenharmony_ci pm3fb_fix.mmio_start = pci_resource_start(dev, 0); 134262306a36Sopenharmony_ci pm3fb_fix.mmio_len = PM3_REGS_SIZE; 134362306a36Sopenharmony_ci#if defined(__BIG_ENDIAN) 134462306a36Sopenharmony_ci pm3fb_fix.mmio_start += PM3_REGS_SIZE; 134562306a36Sopenharmony_ci DPRINTK("Adjusting register base for big-endian.\n"); 134662306a36Sopenharmony_ci#endif 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* Registers - request region and map it. */ 134962306a36Sopenharmony_ci if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, 135062306a36Sopenharmony_ci "pm3fb regbase")) { 135162306a36Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n"); 135262306a36Sopenharmony_ci goto err_exit_neither; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci par->v_regs = 135562306a36Sopenharmony_ci ioremap(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 135662306a36Sopenharmony_ci if (!par->v_regs) { 135762306a36Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n", 135862306a36Sopenharmony_ci pm3fb_fix.id); 135962306a36Sopenharmony_ci release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 136062306a36Sopenharmony_ci goto err_exit_neither; 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci /* Linear frame buffer - request region and map it. */ 136462306a36Sopenharmony_ci pm3fb_fix.smem_start = pci_resource_start(dev, 1); 136562306a36Sopenharmony_ci pm3fb_fix.smem_len = pm3fb_size_memory(par); 136662306a36Sopenharmony_ci if (!pm3fb_fix.smem_len) { 136762306a36Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); 136862306a36Sopenharmony_ci goto err_exit_mmio; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, 137162306a36Sopenharmony_ci "pm3fb smem")) { 137262306a36Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); 137362306a36Sopenharmony_ci goto err_exit_mmio; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci info->screen_base = ioremap_wc(pm3fb_fix.smem_start, 137662306a36Sopenharmony_ci pm3fb_fix.smem_len); 137762306a36Sopenharmony_ci if (!info->screen_base) { 137862306a36Sopenharmony_ci printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); 137962306a36Sopenharmony_ci release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 138062306a36Sopenharmony_ci goto err_exit_mmio; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci info->screen_size = pm3fb_fix.smem_len; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci if (!nomtrr) 138562306a36Sopenharmony_ci par->wc_cookie = arch_phys_wc_add(pm3fb_fix.smem_start, 138662306a36Sopenharmony_ci pm3fb_fix.smem_len); 138762306a36Sopenharmony_ci info->fbops = &pm3fb_ops; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci par->video = PM3_READ_REG(par, PM3VideoControl); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci info->fix = pm3fb_fix; 139262306a36Sopenharmony_ci info->pseudo_palette = par->palette; 139362306a36Sopenharmony_ci info->flags = FBINFO_HWACCEL_XPAN | 139462306a36Sopenharmony_ci FBINFO_HWACCEL_YPAN | 139562306a36Sopenharmony_ci FBINFO_HWACCEL_COPYAREA | 139662306a36Sopenharmony_ci FBINFO_HWACCEL_IMAGEBLIT | 139762306a36Sopenharmony_ci FBINFO_HWACCEL_FILLRECT; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci if (noaccel) { 140062306a36Sopenharmony_ci printk(KERN_DEBUG "disabling acceleration\n"); 140162306a36Sopenharmony_ci info->flags |= FBINFO_HWACCEL_DISABLED; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL); 140462306a36Sopenharmony_ci if (!info->pixmap.addr) { 140562306a36Sopenharmony_ci retval = -ENOMEM; 140662306a36Sopenharmony_ci goto err_exit_pixmap; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci info->pixmap.size = PM3_PIXMAP_SIZE; 140962306a36Sopenharmony_ci info->pixmap.buf_align = 4; 141062306a36Sopenharmony_ci info->pixmap.scan_align = 4; 141162306a36Sopenharmony_ci info->pixmap.access_align = 32; 141262306a36Sopenharmony_ci info->pixmap.flags = FB_PIXMAP_SYSTEM; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci /* 141562306a36Sopenharmony_ci * This should give a reasonable default video mode. The following is 141662306a36Sopenharmony_ci * done when we can set a video mode. 141762306a36Sopenharmony_ci */ 141862306a36Sopenharmony_ci if (!mode_option) 141962306a36Sopenharmony_ci mode_option = "640x480@60"; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (!retval || retval == 4) { 142462306a36Sopenharmony_ci retval = -EINVAL; 142562306a36Sopenharmony_ci goto err_exit_both; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { 142962306a36Sopenharmony_ci retval = -ENOMEM; 143062306a36Sopenharmony_ci goto err_exit_both; 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* 143462306a36Sopenharmony_ci * For drivers that can... 143562306a36Sopenharmony_ci */ 143662306a36Sopenharmony_ci pm3fb_check_var(&info->var, info); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (register_framebuffer(info) < 0) { 143962306a36Sopenharmony_ci retval = -EINVAL; 144062306a36Sopenharmony_ci goto err_exit_all; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci fb_info(info, "%s frame buffer device\n", info->fix.id); 144362306a36Sopenharmony_ci pci_set_drvdata(dev, info); 144462306a36Sopenharmony_ci return 0; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci err_exit_all: 144762306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 144862306a36Sopenharmony_ci err_exit_both: 144962306a36Sopenharmony_ci kfree(info->pixmap.addr); 145062306a36Sopenharmony_ci err_exit_pixmap: 145162306a36Sopenharmony_ci iounmap(info->screen_base); 145262306a36Sopenharmony_ci release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); 145362306a36Sopenharmony_ci err_exit_mmio: 145462306a36Sopenharmony_ci iounmap(par->v_regs); 145562306a36Sopenharmony_ci release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); 145662306a36Sopenharmony_ci err_exit_neither: 145762306a36Sopenharmony_ci framebuffer_release(info); 145862306a36Sopenharmony_ci return retval; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* 146262306a36Sopenharmony_ci * Cleanup 146362306a36Sopenharmony_ci */ 146462306a36Sopenharmony_cistatic void pm3fb_remove(struct pci_dev *dev) 146562306a36Sopenharmony_ci{ 146662306a36Sopenharmony_ci struct fb_info *info = pci_get_drvdata(dev); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (info) { 146962306a36Sopenharmony_ci struct fb_fix_screeninfo *fix = &info->fix; 147062306a36Sopenharmony_ci struct pm3_par *par = info->par; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci unregister_framebuffer(info); 147362306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci arch_phys_wc_del(par->wc_cookie); 147662306a36Sopenharmony_ci iounmap(info->screen_base); 147762306a36Sopenharmony_ci release_mem_region(fix->smem_start, fix->smem_len); 147862306a36Sopenharmony_ci iounmap(par->v_regs); 147962306a36Sopenharmony_ci release_mem_region(fix->mmio_start, fix->mmio_len); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci kfree(info->pixmap.addr); 148262306a36Sopenharmony_ci framebuffer_release(info); 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_cistatic const struct pci_device_id pm3fb_id_table[] = { 148762306a36Sopenharmony_ci { PCI_VENDOR_ID_3DLABS, 0x0a, 148862306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 148962306a36Sopenharmony_ci { 0, } 149062306a36Sopenharmony_ci}; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci/* For PCI drivers */ 149362306a36Sopenharmony_cistatic struct pci_driver pm3fb_driver = { 149462306a36Sopenharmony_ci .name = "pm3fb", 149562306a36Sopenharmony_ci .id_table = pm3fb_id_table, 149662306a36Sopenharmony_ci .probe = pm3fb_probe, 149762306a36Sopenharmony_ci .remove = pm3fb_remove, 149862306a36Sopenharmony_ci}; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pm3fb_id_table); 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci#ifndef MODULE 150362306a36Sopenharmony_ci /* 150462306a36Sopenharmony_ci * Setup 150562306a36Sopenharmony_ci */ 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci/* 150862306a36Sopenharmony_ci * Only necessary if your driver takes special options, 150962306a36Sopenharmony_ci * otherwise we fall back on the generic fb_setup(). 151062306a36Sopenharmony_ci */ 151162306a36Sopenharmony_cistatic int __init pm3fb_setup(char *options) 151262306a36Sopenharmony_ci{ 151362306a36Sopenharmony_ci char *this_opt; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci /* Parse user specified options (`video=pm3fb:') */ 151662306a36Sopenharmony_ci if (!options || !*options) 151762306a36Sopenharmony_ci return 0; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci while ((this_opt = strsep(&options, ",")) != NULL) { 152062306a36Sopenharmony_ci if (!*this_opt) 152162306a36Sopenharmony_ci continue; 152262306a36Sopenharmony_ci else if (!strncmp(this_opt, "noaccel", 7)) 152362306a36Sopenharmony_ci noaccel = 1; 152462306a36Sopenharmony_ci else if (!strncmp(this_opt, "hwcursor=", 9)) 152562306a36Sopenharmony_ci hwcursor = simple_strtoul(this_opt + 9, NULL, 0); 152662306a36Sopenharmony_ci else if (!strncmp(this_opt, "nomtrr", 6)) 152762306a36Sopenharmony_ci nomtrr = 1; 152862306a36Sopenharmony_ci else 152962306a36Sopenharmony_ci mode_option = this_opt; 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci return 0; 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci#endif /* MODULE */ 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_cistatic int __init pm3fb_init(void) 153662306a36Sopenharmony_ci{ 153762306a36Sopenharmony_ci /* 153862306a36Sopenharmony_ci * For kernel boot options (in 'video=pm3fb:<options>' format) 153962306a36Sopenharmony_ci */ 154062306a36Sopenharmony_ci#ifndef MODULE 154162306a36Sopenharmony_ci char *option = NULL; 154262306a36Sopenharmony_ci#endif 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci if (fb_modesetting_disabled("pm3fb")) 154562306a36Sopenharmony_ci return -ENODEV; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci#ifndef MODULE 154862306a36Sopenharmony_ci if (fb_get_options("pm3fb", &option)) 154962306a36Sopenharmony_ci return -ENODEV; 155062306a36Sopenharmony_ci pm3fb_setup(option); 155162306a36Sopenharmony_ci#endif 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci return pci_register_driver(&pm3fb_driver); 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci#ifdef MODULE 155762306a36Sopenharmony_cistatic void __exit pm3fb_exit(void) 155862306a36Sopenharmony_ci{ 155962306a36Sopenharmony_ci pci_unregister_driver(&pm3fb_driver); 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cimodule_exit(pm3fb_exit); 156362306a36Sopenharmony_ci#endif 156462306a36Sopenharmony_cimodule_init(pm3fb_init); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cimodule_param(mode_option, charp, 0); 156762306a36Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); 156862306a36Sopenharmony_cimodule_param(noaccel, bool, 0); 156962306a36Sopenharmony_ciMODULE_PARM_DESC(noaccel, "Disable acceleration"); 157062306a36Sopenharmony_cimodule_param(hwcursor, int, 0644); 157162306a36Sopenharmony_ciMODULE_PARM_DESC(hwcursor, "Enable hardware cursor " 157262306a36Sopenharmony_ci "(1=enable, 0=disable, default=1)"); 157362306a36Sopenharmony_cimodule_param(nomtrr, bool, 0); 157462306a36Sopenharmony_ciMODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ciMODULE_DESCRIPTION("Permedia3 framebuffer device driver"); 157762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1578