cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pm3fb.c (43003B)


      1/*
      2 *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
      3 *
      4 *  Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
      5 *
      6 *  Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
      7 *	based on pm2fb.c
      8 *
      9 *  Based on code written by:
     10 *	   Sven Luther, <luther@dpt-info.u-strasbg.fr>
     11 *	   Alan Hourihane, <alanh@fairlite.demon.co.uk>
     12 *	   Russell King, <rmk@arm.linux.org.uk>
     13 *  Based on linux/drivers/video/skeletonfb.c:
     14 *	Copyright (C) 1997 Geert Uytterhoeven
     15 *  Based on linux/driver/video/pm2fb.c:
     16 *	Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
     17 *	Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
     18 *
     19 *  This file is subject to the terms and conditions of the GNU General Public
     20 *  License. See the file COPYING in the main directory of this archive for
     21 *  more details.
     22 *
     23 */
     24
     25#include <linux/module.h>
     26#include <linux/kernel.h>
     27#include <linux/errno.h>
     28#include <linux/string.h>
     29#include <linux/mm.h>
     30#include <linux/slab.h>
     31#include <linux/delay.h>
     32#include <linux/fb.h>
     33#include <linux/init.h>
     34#include <linux/pci.h>
     35
     36#include <video/pm3fb.h>
     37
     38#if !defined(CONFIG_PCI)
     39#error "Only generic PCI cards supported."
     40#endif
     41
     42#undef PM3FB_MASTER_DEBUG
     43#ifdef PM3FB_MASTER_DEBUG
     44#define DPRINTK(a, b...)	\
     45	printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b)
     46#else
     47#define DPRINTK(a, b...)	no_printk(a, ##b)
     48#endif
     49
     50#define PM3_PIXMAP_SIZE	(2048 * 4)
     51
     52/*
     53 * Driver data
     54 */
     55static int hwcursor = 1;
     56static char *mode_option;
     57static bool noaccel;
     58static bool nomtrr;
     59
     60/*
     61 * This structure defines the hardware state of the graphics card. Normally
     62 * you place this in a header file in linux/include/video. This file usually
     63 * also includes register information. That allows other driver subsystems
     64 * and userland applications the ability to use the same header file to
     65 * avoid duplicate work and easy porting of software.
     66 */
     67struct pm3_par {
     68	unsigned char	__iomem *v_regs;/* virtual address of p_regs */
     69	u32		video;		/* video flags before blanking */
     70	u32		base;		/* screen base in 128 bits unit */
     71	u32		palette[16];
     72	int		wc_cookie;
     73};
     74
     75/*
     76 * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
     77 * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
     78 * to get a fb_var_screeninfo. Otherwise define a default var as well.
     79 */
     80static struct fb_fix_screeninfo pm3fb_fix = {
     81	.id =		"Permedia3",
     82	.type =		FB_TYPE_PACKED_PIXELS,
     83	.visual =	FB_VISUAL_PSEUDOCOLOR,
     84	.xpanstep =	1,
     85	.ypanstep =	1,
     86	.ywrapstep =	0,
     87	.accel =	FB_ACCEL_3DLABS_PERMEDIA3,
     88};
     89
     90/*
     91 * Utility functions
     92 */
     93
     94static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
     95{
     96	return fb_readl(par->v_regs + off);
     97}
     98
     99static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
    100{
    101	fb_writel(v, par->v_regs + off);
    102}
    103
    104static inline void PM3_WAIT(struct pm3_par *par, u32 n)
    105{
    106	while (PM3_READ_REG(par, PM3InFIFOSpace) < n)
    107		cpu_relax();
    108}
    109
    110static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
    111{
    112	PM3_WAIT(par, 3);
    113	PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff);
    114	PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff);
    115	wmb();
    116	PM3_WRITE_REG(par, PM3RD_IndexedData, v);
    117	wmb();
    118}
    119
    120static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
    121			unsigned char r, unsigned char g, unsigned char b)
    122{
    123	PM3_WAIT(par, 4);
    124	PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
    125	wmb();
    126	PM3_WRITE_REG(par, PM3RD_PaletteData, r);
    127	wmb();
    128	PM3_WRITE_REG(par, PM3RD_PaletteData, g);
    129	wmb();
    130	PM3_WRITE_REG(par, PM3RD_PaletteData, b);
    131	wmb();
    132}
    133
    134static void pm3fb_clear_colormap(struct pm3_par *par,
    135			unsigned char r, unsigned char g, unsigned char b)
    136{
    137	int i;
    138
    139	for (i = 0; i < 256 ; i++)
    140		pm3fb_set_color(par, i, r, g, b);
    141
    142}
    143
    144/* Calculating various clock parameters */
    145static void pm3fb_calculate_clock(unsigned long reqclock,
    146				unsigned char *prescale,
    147				unsigned char *feedback,
    148				unsigned char *postscale)
    149{
    150	int f, pre, post;
    151	unsigned long freq;
    152	long freqerr = 1000;
    153	long currerr;
    154
    155	for (f = 1; f < 256; f++) {
    156		for (pre = 1; pre < 256; pre++) {
    157			for (post = 0; post < 5; post++) {
    158				freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
    159				currerr = (reqclock > freq)
    160					? reqclock - freq
    161					: freq - reqclock;
    162				if (currerr < freqerr) {
    163					freqerr = currerr;
    164					*feedback = f;
    165					*prescale = pre;
    166					*postscale = post;
    167				}
    168			}
    169		}
    170	}
    171}
    172
    173static inline int pm3fb_depth(const struct fb_var_screeninfo *var)
    174{
    175	if (var->bits_per_pixel == 16)
    176		return var->red.length + var->green.length
    177			+ var->blue.length;
    178
    179	return var->bits_per_pixel;
    180}
    181
    182static inline int pm3fb_shift_bpp(unsigned bpp, int v)
    183{
    184	switch (bpp) {
    185	case 8:
    186		return (v >> 4);
    187	case 16:
    188		return (v >> 3);
    189	case 32:
    190		return (v >> 2);
    191	}
    192	DPRINTK("Unsupported depth %u\n", bpp);
    193	return 0;
    194}
    195
    196/* acceleration */
    197static int pm3fb_sync(struct fb_info *info)
    198{
    199	struct pm3_par *par = info->par;
    200
    201	PM3_WAIT(par, 2);
    202	PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
    203	PM3_WRITE_REG(par, PM3Sync, 0);
    204	mb();
    205	do {
    206		while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0)
    207			cpu_relax();
    208	} while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag);
    209
    210	return 0;
    211}
    212
    213static void pm3fb_init_engine(struct fb_info *info)
    214{
    215	struct pm3_par *par = info->par;
    216	const u32 width = (info->var.xres_virtual + 7) & ~7;
    217
    218	PM3_WAIT(par, 50);
    219	PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
    220	PM3_WRITE_REG(par, PM3StatisticMode, 0x0);
    221	PM3_WRITE_REG(par, PM3DeltaMode, 0x0);
    222	PM3_WRITE_REG(par, PM3RasterizerMode, 0x0);
    223	PM3_WRITE_REG(par, PM3ScissorMode, 0x0);
    224	PM3_WRITE_REG(par, PM3LineStippleMode, 0x0);
    225	PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0);
    226	PM3_WRITE_REG(par, PM3GIDMode, 0x0);
    227	PM3_WRITE_REG(par, PM3DepthMode, 0x0);
    228	PM3_WRITE_REG(par, PM3StencilMode, 0x0);
    229	PM3_WRITE_REG(par, PM3StencilData, 0x0);
    230	PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0);
    231	PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0);
    232	PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0);
    233	PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0);
    234	PM3_WRITE_REG(par, PM3TextureReadMode, 0x0);
    235	PM3_WRITE_REG(par, PM3LUTMode, 0x0);
    236	PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0);
    237	PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0);
    238	PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0);
    239	PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0);
    240	PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0);
    241	PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0);
    242	PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0);
    243	PM3_WRITE_REG(par, PM3FogMode, 0x0);
    244	PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0);
    245	PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0);
    246	PM3_WRITE_REG(par, PM3AntialiasMode, 0x0);
    247	PM3_WRITE_REG(par, PM3YUVMode, 0x0);
    248	PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0);
    249	PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0);
    250	PM3_WRITE_REG(par, PM3DitherMode, 0x0);
    251	PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0);
    252	PM3_WRITE_REG(par, PM3RouterMode, 0x0);
    253	PM3_WRITE_REG(par, PM3Window, 0x0);
    254
    255	PM3_WRITE_REG(par, PM3Config2D, 0x0);
    256
    257	PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff);
    258
    259	PM3_WRITE_REG(par, PM3XBias, 0x0);
    260	PM3_WRITE_REG(par, PM3YBias, 0x0);
    261	PM3_WRITE_REG(par, PM3DeltaControl, 0x0);
    262
    263	PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff);
    264
    265	PM3_WRITE_REG(par, PM3FBDestReadEnables,
    266			   PM3FBDestReadEnables_E(0xff) |
    267			   PM3FBDestReadEnables_R(0xff) |
    268			   PM3FBDestReadEnables_ReferenceAlpha(0xff));
    269	PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0);
    270	PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0);
    271	PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0,
    272			   PM3FBDestReadBufferWidth_Width(width));
    273
    274	PM3_WRITE_REG(par, PM3FBDestReadMode,
    275			   PM3FBDestReadMode_ReadEnable |
    276			   PM3FBDestReadMode_Enable0);
    277	PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0);
    278	PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0);
    279	PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth,
    280			   PM3FBSourceReadBufferWidth_Width(width));
    281	PM3_WRITE_REG(par, PM3FBSourceReadMode,
    282			   PM3FBSourceReadMode_Blocking |
    283			   PM3FBSourceReadMode_ReadEnable);
    284
    285	PM3_WAIT(par, 2);
    286	{
    287		/* invert bits in bitmask */
    288		unsigned long rm = 1 | (3 << 7);
    289		switch (info->var.bits_per_pixel) {
    290		case 8:
    291			PM3_WRITE_REG(par, PM3PixelSize,
    292					   PM3PixelSize_GLOBAL_8BIT);
    293#ifdef __BIG_ENDIAN
    294			rm |= 3 << 15;
    295#endif
    296			break;
    297		case 16:
    298			PM3_WRITE_REG(par, PM3PixelSize,
    299					   PM3PixelSize_GLOBAL_16BIT);
    300#ifdef __BIG_ENDIAN
    301			rm |= 2 << 15;
    302#endif
    303			break;
    304		case 32:
    305			PM3_WRITE_REG(par, PM3PixelSize,
    306					   PM3PixelSize_GLOBAL_32BIT);
    307			break;
    308		default:
    309			DPRINTK("Unsupported depth %d\n",
    310				info->var.bits_per_pixel);
    311			break;
    312		}
    313		PM3_WRITE_REG(par, PM3RasterizerMode, rm);
    314	}
    315
    316	PM3_WAIT(par, 20);
    317	PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff);
    318	PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff);
    319	PM3_WRITE_REG(par, PM3FBWriteMode,
    320			   PM3FBWriteMode_WriteEnable |
    321			   PM3FBWriteMode_OpaqueSpan |
    322			   PM3FBWriteMode_Enable0);
    323	PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0);
    324	PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0);
    325	PM3_WRITE_REG(par, PM3FBWriteBufferWidth0,
    326			   PM3FBWriteBufferWidth_Width(width));
    327
    328	PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0);
    329	{
    330		/* size in lines of FB */
    331		unsigned long sofb = info->screen_size /
    332			info->fix.line_length;
    333		if (sofb > 4095)
    334			PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095);
    335		else
    336			PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb);
    337
    338		switch (info->var.bits_per_pixel) {
    339		case 8:
    340			PM3_WRITE_REG(par, PM3DitherMode,
    341					   (1 << 10) | (2 << 3));
    342			break;
    343		case 16:
    344			PM3_WRITE_REG(par, PM3DitherMode,
    345					   (1 << 10) | (1 << 3));
    346			break;
    347		case 32:
    348			PM3_WRITE_REG(par, PM3DitherMode,
    349					   (1 << 10) | (0 << 3));
    350			break;
    351		default:
    352			DPRINTK("Unsupported depth %d\n",
    353				info->var.bits_per_pixel);
    354			break;
    355		}
    356	}
    357
    358	PM3_WRITE_REG(par, PM3dXDom, 0x0);
    359	PM3_WRITE_REG(par, PM3dXSub, 0x0);
    360	PM3_WRITE_REG(par, PM3dY, 1 << 16);
    361	PM3_WRITE_REG(par, PM3StartXDom, 0x0);
    362	PM3_WRITE_REG(par, PM3StartXSub, 0x0);
    363	PM3_WRITE_REG(par, PM3StartY, 0x0);
    364	PM3_WRITE_REG(par, PM3Count, 0x0);
    365
    366/* Disable LocalBuffer. better safe than sorry */
    367	PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0);
    368	PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0);
    369	PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0);
    370	PM3_WRITE_REG(par, PM3LBWriteMode, 0x0);
    371
    372	pm3fb_sync(info);
    373}
    374
    375static void pm3fb_fillrect(struct fb_info *info,
    376				const struct fb_fillrect *region)
    377{
    378	struct pm3_par *par = info->par;
    379	struct fb_fillrect modded;
    380	int vxres, vyres;
    381	int rop;
    382	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
    383		((u32 *)info->pseudo_palette)[region->color] : region->color;
    384
    385	if (info->state != FBINFO_STATE_RUNNING)
    386		return;
    387	if (info->flags & FBINFO_HWACCEL_DISABLED) {
    388		cfb_fillrect(info, region);
    389		return;
    390	}
    391	if (region->rop == ROP_COPY )
    392		rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */
    393	else
    394		rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */
    395			PM3Config2D_FBDestReadEnable;
    396
    397	vxres = info->var.xres_virtual;
    398	vyres = info->var.yres_virtual;
    399
    400	memcpy(&modded, region, sizeof(struct fb_fillrect));
    401
    402	if (!modded.width || !modded.height ||
    403	    modded.dx >= vxres || modded.dy >= vyres)
    404		return;
    405
    406	if (modded.dx + modded.width  > vxres)
    407		modded.width  = vxres - modded.dx;
    408	if (modded.dy + modded.height > vyres)
    409		modded.height = vyres - modded.dy;
    410
    411	if (info->var.bits_per_pixel == 8)
    412		color |= color << 8;
    413	if (info->var.bits_per_pixel <= 16)
    414		color |= color << 16;
    415
    416	PM3_WAIT(par, 4);
    417	/* ROP Ox3 is GXcopy */
    418	PM3_WRITE_REG(par, PM3Config2D,
    419			PM3Config2D_UseConstantSource |
    420			PM3Config2D_ForegroundROPEnable |
    421			rop |
    422			PM3Config2D_FBWriteEnable);
    423
    424	PM3_WRITE_REG(par, PM3ForegroundColor, color);
    425
    426	PM3_WRITE_REG(par, PM3RectanglePosition,
    427			PM3RectanglePosition_XOffset(modded.dx) |
    428			PM3RectanglePosition_YOffset(modded.dy));
    429
    430	PM3_WRITE_REG(par, PM3Render2D,
    431		      PM3Render2D_XPositive |
    432		      PM3Render2D_YPositive |
    433		      PM3Render2D_Operation_Normal |
    434		      PM3Render2D_SpanOperation |
    435		      PM3Render2D_Width(modded.width) |
    436		      PM3Render2D_Height(modded.height));
    437}
    438
    439static void pm3fb_copyarea(struct fb_info *info,
    440				const struct fb_copyarea *area)
    441{
    442	struct pm3_par *par = info->par;
    443	struct fb_copyarea modded;
    444	u32 vxres, vyres;
    445	int x_align, o_x, o_y;
    446
    447	if (info->state != FBINFO_STATE_RUNNING)
    448		return;
    449	if (info->flags & FBINFO_HWACCEL_DISABLED) {
    450		cfb_copyarea(info, area);
    451		return;
    452	}
    453
    454	memcpy(&modded, area, sizeof(struct fb_copyarea));
    455
    456	vxres = info->var.xres_virtual;
    457	vyres = info->var.yres_virtual;
    458
    459	if (!modded.width || !modded.height ||
    460	    modded.sx >= vxres || modded.sy >= vyres ||
    461	    modded.dx >= vxres || modded.dy >= vyres)
    462		return;
    463
    464	if (modded.sx + modded.width > vxres)
    465		modded.width = vxres - modded.sx;
    466	if (modded.dx + modded.width > vxres)
    467		modded.width = vxres - modded.dx;
    468	if (modded.sy + modded.height > vyres)
    469		modded.height = vyres - modded.sy;
    470	if (modded.dy + modded.height > vyres)
    471		modded.height = vyres - modded.dy;
    472
    473	o_x = modded.sx - modded.dx;	/*(sx > dx ) ? (sx - dx) : (dx - sx); */
    474	o_y = modded.sy - modded.dy;	/*(sy > dy ) ? (sy - dy) : (dy - sy); */
    475
    476	x_align = (modded.sx & 0x1f);
    477
    478	PM3_WAIT(par, 6);
    479
    480	PM3_WRITE_REG(par, PM3Config2D,
    481			PM3Config2D_UserScissorEnable |
    482			PM3Config2D_ForegroundROPEnable |
    483			PM3Config2D_Blocking |
    484			PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */
    485			PM3Config2D_FBWriteEnable);
    486
    487	PM3_WRITE_REG(par, PM3ScissorMinXY,
    488			((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff));
    489	PM3_WRITE_REG(par, PM3ScissorMaxXY,
    490			(((modded.dy + modded.height) & 0x0fff) << 16) |
    491			((modded.dx + modded.width) & 0x0fff));
    492
    493	PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset,
    494			PM3FBSourceReadBufferOffset_XOffset(o_x) |
    495			PM3FBSourceReadBufferOffset_YOffset(o_y));
    496
    497	PM3_WRITE_REG(par, PM3RectanglePosition,
    498			PM3RectanglePosition_XOffset(modded.dx - x_align) |
    499			PM3RectanglePosition_YOffset(modded.dy));
    500
    501	PM3_WRITE_REG(par, PM3Render2D,
    502			((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) |
    503			((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) |
    504			PM3Render2D_Operation_Normal |
    505			PM3Render2D_SpanOperation |
    506			PM3Render2D_FBSourceReadEnable |
    507			PM3Render2D_Width(modded.width + x_align) |
    508			PM3Render2D_Height(modded.height));
    509}
    510
    511static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image)
    512{
    513	struct pm3_par *par = info->par;
    514	u32 height = image->height;
    515	u32 fgx, bgx;
    516	const u32 *src = (const u32 *)image->data;
    517
    518	if (info->state != FBINFO_STATE_RUNNING)
    519		return;
    520	if (info->flags & FBINFO_HWACCEL_DISABLED) {
    521		cfb_imageblit(info, image);
    522		return;
    523	}
    524	switch (info->fix.visual) {
    525	case FB_VISUAL_PSEUDOCOLOR:
    526		fgx = image->fg_color;
    527		bgx = image->bg_color;
    528		break;
    529	case FB_VISUAL_TRUECOLOR:
    530	default:
    531		fgx = par->palette[image->fg_color];
    532		bgx = par->palette[image->bg_color];
    533		break;
    534	}
    535	if (image->depth != 1) {
    536		cfb_imageblit(info, image);
    537		return;
    538	}
    539
    540	if (info->var.bits_per_pixel == 8) {
    541		fgx |= fgx << 8;
    542		bgx |= bgx << 8;
    543	}
    544	if (info->var.bits_per_pixel <= 16) {
    545		fgx |= fgx << 16;
    546		bgx |= bgx << 16;
    547	}
    548
    549	PM3_WAIT(par, 7);
    550
    551	PM3_WRITE_REG(par, PM3ForegroundColor, fgx);
    552	PM3_WRITE_REG(par, PM3BackgroundColor, bgx);
    553
    554	/* ROP Ox3 is GXcopy */
    555	PM3_WRITE_REG(par, PM3Config2D,
    556			PM3Config2D_UserScissorEnable |
    557			PM3Config2D_UseConstantSource |
    558			PM3Config2D_ForegroundROPEnable |
    559			PM3Config2D_ForegroundROP(0x3) |
    560			PM3Config2D_OpaqueSpan |
    561			PM3Config2D_FBWriteEnable);
    562	PM3_WRITE_REG(par, PM3ScissorMinXY,
    563			((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff));
    564	PM3_WRITE_REG(par, PM3ScissorMaxXY,
    565			(((image->dy + image->height) & 0x0fff) << 16) |
    566			((image->dx + image->width) & 0x0fff));
    567	PM3_WRITE_REG(par, PM3RectanglePosition,
    568			PM3RectanglePosition_XOffset(image->dx) |
    569			PM3RectanglePosition_YOffset(image->dy));
    570	PM3_WRITE_REG(par, PM3Render2D,
    571			PM3Render2D_XPositive |
    572			PM3Render2D_YPositive |
    573			PM3Render2D_Operation_SyncOnBitMask |
    574			PM3Render2D_SpanOperation |
    575			PM3Render2D_Width(image->width) |
    576			PM3Render2D_Height(image->height));
    577
    578
    579	while (height--) {
    580		int width = ((image->width + 7) >> 3)
    581				+ info->pixmap.scan_align - 1;
    582		width >>= 2;
    583
    584		while (width >= PM3_FIFO_SIZE) {
    585			int i = PM3_FIFO_SIZE - 1;
    586
    587			PM3_WAIT(par, PM3_FIFO_SIZE);
    588			while (i--) {
    589				PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
    590				src++;
    591			}
    592			width -= PM3_FIFO_SIZE - 1;
    593		}
    594
    595		PM3_WAIT(par, width + 1);
    596		while (width--) {
    597			PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
    598			src++;
    599		}
    600	}
    601}
    602/* end of acceleration functions */
    603
    604/*
    605 *	Hardware Cursor support.
    606 */
    607static const u8 cursor_bits_lookup[16] = {
    608	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    609	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
    610};
    611
    612static int pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
    613{
    614	struct pm3_par *par = info->par;
    615	u8 mode;
    616
    617	if (!hwcursor)
    618		return -EINVAL;	/* just to force soft_cursor() call */
    619
    620	/* Too large of a cursor or wrong bpp :-( */
    621	if (cursor->image.width > 64 ||
    622	    cursor->image.height > 64 ||
    623	    cursor->image.depth > 1)
    624		return -EINVAL;
    625
    626	mode = PM3RD_CursorMode_TYPE_X;
    627	if (cursor->enable)
    628		 mode |= PM3RD_CursorMode_CURSOR_ENABLE;
    629
    630	PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode);
    631
    632	/*
    633	 * If the cursor is not be changed this means either we want the
    634	 * current cursor state (if enable is set) or we want to query what
    635	 * we can do with the cursor (if enable is not set)
    636	 */
    637	if (!cursor->set)
    638		return 0;
    639
    640	if (cursor->set & FB_CUR_SETPOS) {
    641		int x = cursor->image.dx - info->var.xoffset;
    642		int y = cursor->image.dy - info->var.yoffset;
    643
    644		PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff);
    645		PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf);
    646		PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff);
    647		PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf);
    648	}
    649
    650	if (cursor->set & FB_CUR_SETHOT) {
    651		PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX,
    652				  cursor->hot.x & 0x3f);
    653		PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY,
    654				  cursor->hot.y & 0x3f);
    655	}
    656
    657	if (cursor->set & FB_CUR_SETCMAP) {
    658		u32 fg_idx = cursor->image.fg_color;
    659		u32 bg_idx = cursor->image.bg_color;
    660		struct fb_cmap cmap = info->cmap;
    661
    662		/* the X11 driver says one should use these color registers */
    663		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39),
    664				  cmap.red[fg_idx] >> 8 );
    665		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40),
    666				  cmap.green[fg_idx] >> 8 );
    667		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41),
    668				  cmap.blue[fg_idx] >> 8 );
    669
    670		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42),
    671				  cmap.red[bg_idx] >> 8 );
    672		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43),
    673				  cmap.green[bg_idx] >> 8 );
    674		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44),
    675				  cmap.blue[bg_idx] >> 8 );
    676	}
    677
    678	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
    679		u8 *bitmap = (u8 *)cursor->image.data;
    680		u8 *mask = (u8 *)cursor->mask;
    681		int i;
    682		int pos = PM3RD_CursorPattern(0);
    683
    684		for (i = 0; i < cursor->image.height; i++) {
    685			int j = (cursor->image.width + 7) >> 3;
    686			int k = 8 - j;
    687
    688			for (; j > 0; j--) {
    689				u8 data = *bitmap ^ *mask;
    690
    691				if (cursor->rop == ROP_COPY)
    692					data = *mask & *bitmap;
    693				/* Upper 4 bits of bitmap data */
    694				PM3_WRITE_DAC_REG(par, pos++,
    695					cursor_bits_lookup[data >> 4] |
    696					(cursor_bits_lookup[*mask >> 4] << 1));
    697				/* Lower 4 bits of bitmap */
    698				PM3_WRITE_DAC_REG(par, pos++,
    699					cursor_bits_lookup[data & 0xf] |
    700					(cursor_bits_lookup[*mask & 0xf] << 1));
    701				bitmap++;
    702				mask++;
    703			}
    704			for (; k > 0; k--) {
    705				PM3_WRITE_DAC_REG(par, pos++, 0);
    706				PM3_WRITE_DAC_REG(par, pos++, 0);
    707			}
    708		}
    709		while (pos < PM3RD_CursorPattern(1024))
    710			PM3_WRITE_DAC_REG(par, pos++, 0);
    711	}
    712	return 0;
    713}
    714
    715/* write the mode to registers */
    716static void pm3fb_write_mode(struct fb_info *info)
    717{
    718	struct pm3_par *par = info->par;
    719	char tempsync = 0x00;
    720	char tempmisc = 0x00;
    721	const u32 hsstart = info->var.right_margin;
    722	const u32 hsend = hsstart + info->var.hsync_len;
    723	const u32 hbend = hsend + info->var.left_margin;
    724	const u32 xres = (info->var.xres + 31) & ~31;
    725	const u32 htotal = xres + hbend;
    726	const u32 vsstart = info->var.lower_margin;
    727	const u32 vsend = vsstart + info->var.vsync_len;
    728	const u32 vbend = vsend + info->var.upper_margin;
    729	const u32 vtotal = info->var.yres + vbend;
    730	const u32 width = (info->var.xres_virtual + 7) & ~7;
    731	const unsigned bpp = info->var.bits_per_pixel;
    732
    733	PM3_WAIT(par, 20);
    734	PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
    735	PM3_WRITE_REG(par, PM3Aperture0, 0x00000000);
    736	PM3_WRITE_REG(par, PM3Aperture1, 0x00000000);
    737	PM3_WRITE_REG(par, PM3FIFODis, 0x00000007);
    738
    739	PM3_WRITE_REG(par, PM3HTotal,
    740			   pm3fb_shift_bpp(bpp, htotal - 1));
    741	PM3_WRITE_REG(par, PM3HsEnd,
    742			   pm3fb_shift_bpp(bpp, hsend));
    743	PM3_WRITE_REG(par, PM3HsStart,
    744			   pm3fb_shift_bpp(bpp, hsstart));
    745	PM3_WRITE_REG(par, PM3HbEnd,
    746			   pm3fb_shift_bpp(bpp, hbend));
    747	PM3_WRITE_REG(par, PM3HgEnd,
    748			   pm3fb_shift_bpp(bpp, hbend));
    749	PM3_WRITE_REG(par, PM3ScreenStride,
    750			   pm3fb_shift_bpp(bpp, width));
    751	PM3_WRITE_REG(par, PM3VTotal, vtotal - 1);
    752	PM3_WRITE_REG(par, PM3VsEnd, vsend - 1);
    753	PM3_WRITE_REG(par, PM3VsStart, vsstart - 1);
    754	PM3_WRITE_REG(par, PM3VbEnd, vbend);
    755
    756	switch (bpp) {
    757	case 8:
    758		PM3_WRITE_REG(par, PM3ByAperture1Mode,
    759				   PM3ByApertureMode_PIXELSIZE_8BIT);
    760		PM3_WRITE_REG(par, PM3ByAperture2Mode,
    761				   PM3ByApertureMode_PIXELSIZE_8BIT);
    762		break;
    763
    764	case 16:
    765#ifndef __BIG_ENDIAN
    766		PM3_WRITE_REG(par, PM3ByAperture1Mode,
    767				   PM3ByApertureMode_PIXELSIZE_16BIT);
    768		PM3_WRITE_REG(par, PM3ByAperture2Mode,
    769				   PM3ByApertureMode_PIXELSIZE_16BIT);
    770#else
    771		PM3_WRITE_REG(par, PM3ByAperture1Mode,
    772				   PM3ByApertureMode_PIXELSIZE_16BIT |
    773				   PM3ByApertureMode_BYTESWAP_BADC);
    774		PM3_WRITE_REG(par, PM3ByAperture2Mode,
    775				   PM3ByApertureMode_PIXELSIZE_16BIT |
    776				   PM3ByApertureMode_BYTESWAP_BADC);
    777#endif /* ! __BIG_ENDIAN */
    778		break;
    779
    780	case 32:
    781#ifndef __BIG_ENDIAN
    782		PM3_WRITE_REG(par, PM3ByAperture1Mode,
    783				   PM3ByApertureMode_PIXELSIZE_32BIT);
    784		PM3_WRITE_REG(par, PM3ByAperture2Mode,
    785				   PM3ByApertureMode_PIXELSIZE_32BIT);
    786#else
    787		PM3_WRITE_REG(par, PM3ByAperture1Mode,
    788				   PM3ByApertureMode_PIXELSIZE_32BIT |
    789				   PM3ByApertureMode_BYTESWAP_DCBA);
    790		PM3_WRITE_REG(par, PM3ByAperture2Mode,
    791				   PM3ByApertureMode_PIXELSIZE_32BIT |
    792				   PM3ByApertureMode_BYTESWAP_DCBA);
    793#endif /* ! __BIG_ENDIAN */
    794		break;
    795
    796	default:
    797		DPRINTK("Unsupported depth %d\n", bpp);
    798		break;
    799	}
    800
    801	/*
    802	 * Oxygen VX1 - it appears that setting PM3VideoControl and
    803	 * then PM3RD_SyncControl to the same SYNC settings undoes
    804	 * any net change - they seem to xor together.  Only set the
    805	 * sync options in PM3RD_SyncControl.  --rmk
    806	 */
    807	{
    808		unsigned int video = par->video;
    809
    810		video &= ~(PM3VideoControl_HSYNC_MASK |
    811			   PM3VideoControl_VSYNC_MASK);
    812		video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
    813			 PM3VideoControl_VSYNC_ACTIVE_HIGH;
    814		PM3_WRITE_REG(par, PM3VideoControl, video);
    815	}
    816	PM3_WRITE_REG(par, PM3VClkCtl,
    817			   (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
    818	PM3_WRITE_REG(par, PM3ScreenBase, par->base);
    819	PM3_WRITE_REG(par, PM3ChipConfig,
    820			   (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
    821
    822	wmb();
    823	{
    824		unsigned char m;	/* ClkPreScale */
    825		unsigned char n;	/* ClkFeedBackScale */
    826		unsigned char p;	/* ClkPostScale */
    827		unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
    828
    829		(void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
    830
    831		DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
    832			pixclock, (int) m, (int) n, (int) p);
    833
    834		PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
    835		PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
    836		PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
    837	}
    838	/*
    839	   PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
    840	 */
    841	/*
    842	   PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
    843	 */
    844	if ((par->video & PM3VideoControl_HSYNC_MASK) ==
    845	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
    846		tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
    847	if ((par->video & PM3VideoControl_VSYNC_MASK) ==
    848	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
    849		tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
    850
    851	PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
    852	DPRINTK("PM3RD_SyncControl: %d\n", tempsync);
    853
    854	PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
    855
    856	switch (pm3fb_depth(&info->var)) {
    857	case 8:
    858		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
    859				  PM3RD_PixelSize_8_BIT_PIXELS);
    860		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
    861				  PM3RD_ColorFormat_CI8_COLOR |
    862				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
    863		tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
    864		break;
    865	case 12:
    866		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
    867				  PM3RD_PixelSize_16_BIT_PIXELS);
    868		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
    869				  PM3RD_ColorFormat_4444_COLOR |
    870				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
    871				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
    872		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
    873			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
    874		break;
    875	case 15:
    876		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
    877				  PM3RD_PixelSize_16_BIT_PIXELS);
    878		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
    879				  PM3RD_ColorFormat_5551_FRONT_COLOR |
    880				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
    881				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
    882		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
    883			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
    884		break;
    885	case 16:
    886		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
    887				  PM3RD_PixelSize_16_BIT_PIXELS);
    888		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
    889				  PM3RD_ColorFormat_565_FRONT_COLOR |
    890				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
    891				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
    892		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
    893			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
    894		break;
    895	case 32:
    896		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
    897				  PM3RD_PixelSize_32_BIT_PIXELS);
    898		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
    899				  PM3RD_ColorFormat_8888_COLOR |
    900				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
    901		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
    902			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
    903		break;
    904	}
    905	PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc);
    906}
    907
    908/*
    909 * hardware independent functions
    910 */
    911static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
    912{
    913	u32 lpitch;
    914	unsigned bpp = var->red.length + var->green.length
    915			+ var->blue.length + var->transp.length;
    916
    917	if (bpp != var->bits_per_pixel) {
    918		/* set predefined mode for bits_per_pixel settings */
    919
    920		switch (var->bits_per_pixel) {
    921		case 8:
    922			var->red.length = 8;
    923			var->green.length = 8;
    924			var->blue.length = 8;
    925			var->red.offset = 0;
    926			var->green.offset = 0;
    927			var->blue.offset = 0;
    928			var->transp.offset = 0;
    929			var->transp.length = 0;
    930			break;
    931		case 16:
    932			var->red.length = 5;
    933			var->blue.length = 5;
    934			var->green.length = 6;
    935			var->transp.length = 0;
    936			break;
    937		case 32:
    938			var->red.length = 8;
    939			var->green.length = 8;
    940			var->blue.length = 8;
    941			var->transp.length = 8;
    942			break;
    943		default:
    944			DPRINTK("depth not supported: %u\n",
    945				var->bits_per_pixel);
    946			return -EINVAL;
    947		}
    948	}
    949	/* it is assumed BGRA order */
    950	if (var->bits_per_pixel > 8 ) {
    951		var->blue.offset = 0;
    952		var->green.offset = var->blue.length;
    953		var->red.offset = var->green.offset + var->green.length;
    954		var->transp.offset = var->red.offset + var->red.length;
    955	}
    956	var->height = -1;
    957	var->width = -1;
    958
    959	if (var->xres != var->xres_virtual) {
    960		DPRINTK("virtual x resolution != "
    961			"physical x resolution not supported\n");
    962		return -EINVAL;
    963	}
    964
    965	if (var->yres > var->yres_virtual) {
    966		DPRINTK("virtual y resolution < "
    967			"physical y resolution not possible\n");
    968		return -EINVAL;
    969	}
    970
    971	if (var->xoffset) {
    972		DPRINTK("xoffset not supported\n");
    973		return -EINVAL;
    974	}
    975
    976	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
    977		DPRINTK("interlace not supported\n");
    978		return -EINVAL;
    979	}
    980
    981	var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
    982	lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
    983
    984	if (var->xres < 200 || var->xres > 2048) {
    985		DPRINTK("width not supported: %u\n", var->xres);
    986		return -EINVAL;
    987	}
    988
    989	if (var->yres < 200 || var->yres > 4095) {
    990		DPRINTK("height not supported: %u\n", var->yres);
    991		return -EINVAL;
    992	}
    993
    994	if (lpitch * var->yres_virtual > info->fix.smem_len) {
    995		DPRINTK("no memory for screen (%ux%ux%u)\n",
    996			var->xres, var->yres_virtual, var->bits_per_pixel);
    997		return -EINVAL;
    998	}
    999
   1000	if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
   1001		DPRINTK("pixclock too high (%ldKHz)\n",
   1002			PICOS2KHZ(var->pixclock));
   1003		return -EINVAL;
   1004	}
   1005
   1006	var->accel_flags = 0;	/* Can't mmap if this is on */
   1007
   1008	DPRINTK("Checking graphics mode at %dx%d depth %d\n",
   1009		var->xres, var->yres, var->bits_per_pixel);
   1010	return 0;
   1011}
   1012
   1013static int pm3fb_set_par(struct fb_info *info)
   1014{
   1015	struct pm3_par *par = info->par;
   1016	const u32 xres = (info->var.xres + 31) & ~31;
   1017	const unsigned bpp = info->var.bits_per_pixel;
   1018
   1019	par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres)
   1020					+ info->var.xoffset);
   1021	par->video = 0;
   1022
   1023	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
   1024		par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
   1025	else
   1026		par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
   1027
   1028	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
   1029		par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
   1030	else
   1031		par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
   1032
   1033	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
   1034		par->video |= PM3VideoControl_LINE_DOUBLE_ON;
   1035
   1036	if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
   1037		par->video |= PM3VideoControl_ENABLE;
   1038	else
   1039		DPRINTK("PM3Video disabled\n");
   1040
   1041	switch (bpp) {
   1042	case 8:
   1043		par->video |= PM3VideoControl_PIXELSIZE_8BIT;
   1044		break;
   1045	case 16:
   1046		par->video |= PM3VideoControl_PIXELSIZE_16BIT;
   1047		break;
   1048	case 32:
   1049		par->video |= PM3VideoControl_PIXELSIZE_32BIT;
   1050		break;
   1051	default:
   1052		DPRINTK("Unsupported depth\n");
   1053		break;
   1054	}
   1055
   1056	info->fix.visual =
   1057		(bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
   1058	info->fix.line_length = ((info->var.xres_virtual + 7)  >> 3) * bpp;
   1059
   1060/*	pm3fb_clear_memory(info, 0);*/
   1061	pm3fb_clear_colormap(par, 0, 0, 0);
   1062	PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0);
   1063	pm3fb_init_engine(info);
   1064	pm3fb_write_mode(info);
   1065	return 0;
   1066}
   1067
   1068static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
   1069			   unsigned blue, unsigned transp,
   1070			   struct fb_info *info)
   1071{
   1072	struct pm3_par *par = info->par;
   1073
   1074	if (regno >= 256)  /* no. of hw registers */
   1075	   return -EINVAL;
   1076
   1077	/* grayscale works only partially under directcolor */
   1078	/* grayscale = 0.30*R + 0.59*G + 0.11*B */
   1079	if (info->var.grayscale)
   1080	   red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
   1081
   1082	/* Directcolor:
   1083	 *   var->{color}.offset contains start of bitfield
   1084	 *   var->{color}.length contains length of bitfield
   1085	 *   {hardwarespecific} contains width of DAC
   1086	 *   pseudo_palette[X] is programmed to (X << red.offset) |
   1087	 *					(X << green.offset) |
   1088	 *					(X << blue.offset)
   1089	 *   RAMDAC[X] is programmed to (red, green, blue)
   1090	 *   color depth = SUM(var->{color}.length)
   1091	 *
   1092	 * Pseudocolor:
   1093	 *	var->{color}.offset is 0
   1094	 *	var->{color}.length contains width of DAC or the number
   1095	 *			of unique colors available (color depth)
   1096	 *	pseudo_palette is not used
   1097	 *	RAMDAC[X] is programmed to (red, green, blue)
   1098	 *	color depth = var->{color}.length
   1099	 */
   1100
   1101	/*
   1102	 * This is the point where the color is converted to something that
   1103	 * is acceptable by the hardware.
   1104	 */
   1105#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
   1106	red = CNVT_TOHW(red, info->var.red.length);
   1107	green = CNVT_TOHW(green, info->var.green.length);
   1108	blue = CNVT_TOHW(blue, info->var.blue.length);
   1109	transp = CNVT_TOHW(transp, info->var.transp.length);
   1110#undef CNVT_TOHW
   1111
   1112	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
   1113	info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
   1114		u32 v;
   1115
   1116		if (regno >= 16)
   1117			return -EINVAL;
   1118
   1119		v = (red << info->var.red.offset) |
   1120			(green << info->var.green.offset) |
   1121			(blue << info->var.blue.offset) |
   1122			(transp << info->var.transp.offset);
   1123
   1124		switch (info->var.bits_per_pixel) {
   1125		case 8:
   1126			break;
   1127		case 16:
   1128		case 32:
   1129			((u32 *)(info->pseudo_palette))[regno] = v;
   1130			break;
   1131		}
   1132		return 0;
   1133	} else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
   1134		pm3fb_set_color(par, regno, red, green, blue);
   1135
   1136	return 0;
   1137}
   1138
   1139static int pm3fb_pan_display(struct fb_var_screeninfo *var,
   1140				 struct fb_info *info)
   1141{
   1142	struct pm3_par *par = info->par;
   1143	const u32 xres = (info->var.xres + 31) & ~31;
   1144
   1145	par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
   1146					(var->yoffset * xres)
   1147					+ var->xoffset);
   1148	PM3_WAIT(par, 1);
   1149	PM3_WRITE_REG(par, PM3ScreenBase, par->base);
   1150	return 0;
   1151}
   1152
   1153static int pm3fb_blank(int blank_mode, struct fb_info *info)
   1154{
   1155	struct pm3_par *par = info->par;
   1156	u32 video = par->video;
   1157
   1158	/*
   1159	 * Oxygen VX1 - it appears that setting PM3VideoControl and
   1160	 * then PM3RD_SyncControl to the same SYNC settings undoes
   1161	 * any net change - they seem to xor together.  Only set the
   1162	 * sync options in PM3RD_SyncControl.  --rmk
   1163	 */
   1164	video &= ~(PM3VideoControl_HSYNC_MASK |
   1165		   PM3VideoControl_VSYNC_MASK);
   1166	video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
   1167		 PM3VideoControl_VSYNC_ACTIVE_HIGH;
   1168
   1169	switch (blank_mode) {
   1170	case FB_BLANK_UNBLANK:
   1171		video |= PM3VideoControl_ENABLE;
   1172		break;
   1173	case FB_BLANK_NORMAL:
   1174		video &= ~PM3VideoControl_ENABLE;
   1175		break;
   1176	case FB_BLANK_HSYNC_SUSPEND:
   1177		video &= ~(PM3VideoControl_HSYNC_MASK |
   1178			  PM3VideoControl_BLANK_ACTIVE_LOW);
   1179		break;
   1180	case FB_BLANK_VSYNC_SUSPEND:
   1181		video &= ~(PM3VideoControl_VSYNC_MASK |
   1182			  PM3VideoControl_BLANK_ACTIVE_LOW);
   1183		break;
   1184	case FB_BLANK_POWERDOWN:
   1185		video &= ~(PM3VideoControl_HSYNC_MASK |
   1186			  PM3VideoControl_VSYNC_MASK |
   1187			  PM3VideoControl_BLANK_ACTIVE_LOW);
   1188		break;
   1189	default:
   1190		DPRINTK("Unsupported blanking %d\n", blank_mode);
   1191		return 1;
   1192	}
   1193
   1194	PM3_WAIT(par, 1);
   1195	PM3_WRITE_REG(par, PM3VideoControl, video);
   1196	return 0;
   1197}
   1198
   1199	/*
   1200	 *  Frame buffer operations
   1201	 */
   1202
   1203static const struct fb_ops pm3fb_ops = {
   1204	.owner		= THIS_MODULE,
   1205	.fb_check_var	= pm3fb_check_var,
   1206	.fb_set_par	= pm3fb_set_par,
   1207	.fb_setcolreg	= pm3fb_setcolreg,
   1208	.fb_pan_display	= pm3fb_pan_display,
   1209	.fb_fillrect	= pm3fb_fillrect,
   1210	.fb_copyarea	= pm3fb_copyarea,
   1211	.fb_imageblit	= pm3fb_imageblit,
   1212	.fb_blank	= pm3fb_blank,
   1213	.fb_sync	= pm3fb_sync,
   1214	.fb_cursor	= pm3fb_cursor,
   1215};
   1216
   1217/* ------------------------------------------------------------------------- */
   1218
   1219	/*
   1220	 *  Initialization
   1221	 */
   1222
   1223/* mmio register are already mapped when this function is called */
   1224/* the pm3fb_fix.smem_start is also set */
   1225static unsigned long pm3fb_size_memory(struct pm3_par *par)
   1226{
   1227	unsigned long	memsize = 0;
   1228	unsigned long	tempBypass, i, temp1, temp2;
   1229	unsigned char	__iomem *screen_mem;
   1230
   1231	pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */
   1232	/* Linear frame buffer - request region and map it. */
   1233	if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
   1234				 "pm3fb smem")) {
   1235		printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
   1236		return 0;
   1237	}
   1238	screen_mem =
   1239		ioremap(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
   1240	if (!screen_mem) {
   1241		printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
   1242		release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
   1243		return 0;
   1244	}
   1245
   1246	/* TODO: card-specific stuff, *before* accessing *any* FB memory */
   1247	/* For Appian Jeronimo 2000 board second head */
   1248
   1249	tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);
   1250
   1251	DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
   1252
   1253	PM3_WAIT(par, 1);
   1254	PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
   1255
   1256	/* pm3 split up memory, replicates, and do a lot of
   1257	 * nasty stuff IMHO ;-)
   1258	 */
   1259	for (i = 0; i < 32; i++) {
   1260		fb_writel(i * 0x00345678,
   1261			  (screen_mem + (i * 1048576)));
   1262		mb();
   1263		temp1 = fb_readl((screen_mem + (i * 1048576)));
   1264
   1265		/* Let's check for wrapover, write will fail at 16MB boundary */
   1266		if (temp1 == (i * 0x00345678))
   1267			memsize = i;
   1268		else
   1269			break;
   1270	}
   1271
   1272	DPRINTK("First detect pass already got %ld MB\n", memsize + 1);
   1273
   1274	if (memsize + 1 == i) {
   1275		for (i = 0; i < 32; i++) {
   1276			/* Clear first 32MB ; 0 is 0, no need to byteswap */
   1277			writel(0x0000000, (screen_mem + (i * 1048576)));
   1278		}
   1279		wmb();
   1280
   1281		for (i = 32; i < 64; i++) {
   1282			fb_writel(i * 0x00345678,
   1283				  (screen_mem + (i * 1048576)));
   1284			mb();
   1285			temp1 =
   1286			    fb_readl((screen_mem + (i * 1048576)));
   1287			temp2 =
   1288			    fb_readl((screen_mem + ((i - 32) * 1048576)));
   1289			/* different value, different RAM... */
   1290			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
   1291				memsize = i;
   1292			else
   1293				break;
   1294		}
   1295	}
   1296	DPRINTK("Second detect pass got %ld MB\n", memsize + 1);
   1297
   1298	PM3_WAIT(par, 1);
   1299	PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);
   1300
   1301	iounmap(screen_mem);
   1302	release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
   1303	memsize = 1048576 * (memsize + 1);
   1304
   1305	DPRINTK("Returning 0x%08lx bytes\n", memsize);
   1306
   1307	return memsize;
   1308}
   1309
   1310static int pm3fb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
   1311{
   1312	struct fb_info *info;
   1313	struct pm3_par *par;
   1314	struct device *device = &dev->dev; /* for pci drivers */
   1315	int err;
   1316	int retval = -ENXIO;
   1317
   1318	err = pci_enable_device(dev);
   1319	if (err) {
   1320		printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err);
   1321		return err;
   1322	}
   1323	/*
   1324	 * Dynamically allocate info and par
   1325	 */
   1326	info = framebuffer_alloc(sizeof(struct pm3_par), device);
   1327
   1328	if (!info)
   1329		return -ENOMEM;
   1330	par = info->par;
   1331
   1332	/*
   1333	 * Here we set the screen_base to the virtual memory address
   1334	 * for the framebuffer.
   1335	 */
   1336	pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
   1337	pm3fb_fix.mmio_len = PM3_REGS_SIZE;
   1338#if defined(__BIG_ENDIAN)
   1339	pm3fb_fix.mmio_start += PM3_REGS_SIZE;
   1340	DPRINTK("Adjusting register base for big-endian.\n");
   1341#endif
   1342
   1343	/* Registers - request region and map it. */
   1344	if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
   1345				 "pm3fb regbase")) {
   1346		printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n");
   1347		goto err_exit_neither;
   1348	}
   1349	par->v_regs =
   1350		ioremap(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
   1351	if (!par->v_regs) {
   1352		printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",
   1353			pm3fb_fix.id);
   1354		release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
   1355		goto err_exit_neither;
   1356	}
   1357
   1358	/* Linear frame buffer - request region and map it. */
   1359	pm3fb_fix.smem_start = pci_resource_start(dev, 1);
   1360	pm3fb_fix.smem_len = pm3fb_size_memory(par);
   1361	if (!pm3fb_fix.smem_len) {
   1362		printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");
   1363		goto err_exit_mmio;
   1364	}
   1365	if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
   1366				 "pm3fb smem")) {
   1367		printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
   1368		goto err_exit_mmio;
   1369	}
   1370	info->screen_base = ioremap_wc(pm3fb_fix.smem_start,
   1371				       pm3fb_fix.smem_len);
   1372	if (!info->screen_base) {
   1373		printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
   1374		release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
   1375		goto err_exit_mmio;
   1376	}
   1377	info->screen_size = pm3fb_fix.smem_len;
   1378
   1379	if (!nomtrr)
   1380		par->wc_cookie = arch_phys_wc_add(pm3fb_fix.smem_start,
   1381						  pm3fb_fix.smem_len);
   1382	info->fbops = &pm3fb_ops;
   1383
   1384	par->video = PM3_READ_REG(par, PM3VideoControl);
   1385
   1386	info->fix = pm3fb_fix;
   1387	info->pseudo_palette = par->palette;
   1388	info->flags = FBINFO_DEFAULT |
   1389			FBINFO_HWACCEL_XPAN |
   1390			FBINFO_HWACCEL_YPAN |
   1391			FBINFO_HWACCEL_COPYAREA |
   1392			FBINFO_HWACCEL_IMAGEBLIT |
   1393			FBINFO_HWACCEL_FILLRECT;
   1394
   1395	if (noaccel) {
   1396		printk(KERN_DEBUG "disabling acceleration\n");
   1397		info->flags |= FBINFO_HWACCEL_DISABLED;
   1398	}
   1399	info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL);
   1400	if (!info->pixmap.addr) {
   1401		retval = -ENOMEM;
   1402		goto err_exit_pixmap;
   1403	}
   1404	info->pixmap.size = PM3_PIXMAP_SIZE;
   1405	info->pixmap.buf_align = 4;
   1406	info->pixmap.scan_align = 4;
   1407	info->pixmap.access_align = 32;
   1408	info->pixmap.flags = FB_PIXMAP_SYSTEM;
   1409
   1410	/*
   1411	 * This should give a reasonable default video mode. The following is
   1412	 * done when we can set a video mode.
   1413	 */
   1414	if (!mode_option)
   1415		mode_option = "640x480@60";
   1416
   1417	retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
   1418
   1419	if (!retval || retval == 4) {
   1420		retval = -EINVAL;
   1421		goto err_exit_both;
   1422	}
   1423
   1424	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
   1425		retval = -ENOMEM;
   1426		goto err_exit_both;
   1427	}
   1428
   1429	/*
   1430	 * For drivers that can...
   1431	 */
   1432	pm3fb_check_var(&info->var, info);
   1433
   1434	if (register_framebuffer(info) < 0) {
   1435		retval = -EINVAL;
   1436		goto err_exit_all;
   1437	}
   1438	fb_info(info, "%s frame buffer device\n", info->fix.id);
   1439	pci_set_drvdata(dev, info);
   1440	return 0;
   1441
   1442 err_exit_all:
   1443	fb_dealloc_cmap(&info->cmap);
   1444 err_exit_both:
   1445	kfree(info->pixmap.addr);
   1446 err_exit_pixmap:
   1447	iounmap(info->screen_base);
   1448	release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
   1449 err_exit_mmio:
   1450	iounmap(par->v_regs);
   1451	release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
   1452 err_exit_neither:
   1453	framebuffer_release(info);
   1454	return retval;
   1455}
   1456
   1457	/*
   1458	 *  Cleanup
   1459	 */
   1460static void pm3fb_remove(struct pci_dev *dev)
   1461{
   1462	struct fb_info *info = pci_get_drvdata(dev);
   1463
   1464	if (info) {
   1465		struct fb_fix_screeninfo *fix = &info->fix;
   1466		struct pm3_par *par = info->par;
   1467
   1468		unregister_framebuffer(info);
   1469		fb_dealloc_cmap(&info->cmap);
   1470
   1471		arch_phys_wc_del(par->wc_cookie);
   1472		iounmap(info->screen_base);
   1473		release_mem_region(fix->smem_start, fix->smem_len);
   1474		iounmap(par->v_regs);
   1475		release_mem_region(fix->mmio_start, fix->mmio_len);
   1476
   1477		kfree(info->pixmap.addr);
   1478		framebuffer_release(info);
   1479	}
   1480}
   1481
   1482static const struct pci_device_id pm3fb_id_table[] = {
   1483	{ PCI_VENDOR_ID_3DLABS, 0x0a,
   1484	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
   1485	{ 0, }
   1486};
   1487
   1488/* For PCI drivers */
   1489static struct pci_driver pm3fb_driver = {
   1490	.name =		"pm3fb",
   1491	.id_table =	pm3fb_id_table,
   1492	.probe =	pm3fb_probe,
   1493	.remove =	pm3fb_remove,
   1494};
   1495
   1496MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
   1497
   1498#ifndef MODULE
   1499	/*
   1500	 *  Setup
   1501	 */
   1502
   1503/*
   1504 * Only necessary if your driver takes special options,
   1505 * otherwise we fall back on the generic fb_setup().
   1506 */
   1507static int __init pm3fb_setup(char *options)
   1508{
   1509	char *this_opt;
   1510
   1511	/* Parse user specified options (`video=pm3fb:') */
   1512	if (!options || !*options)
   1513		return 0;
   1514
   1515	while ((this_opt = strsep(&options, ",")) != NULL) {
   1516		if (!*this_opt)
   1517			continue;
   1518		else if (!strncmp(this_opt, "noaccel", 7))
   1519			noaccel = 1;
   1520		else if (!strncmp(this_opt, "hwcursor=", 9))
   1521			hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
   1522		else if (!strncmp(this_opt, "nomtrr", 6))
   1523			nomtrr = 1;
   1524		else
   1525			mode_option = this_opt;
   1526	}
   1527	return 0;
   1528}
   1529#endif /* MODULE */
   1530
   1531static int __init pm3fb_init(void)
   1532{
   1533	/*
   1534	 *  For kernel boot options (in 'video=pm3fb:<options>' format)
   1535	 */
   1536#ifndef MODULE
   1537	char *option = NULL;
   1538
   1539	if (fb_get_options("pm3fb", &option))
   1540		return -ENODEV;
   1541	pm3fb_setup(option);
   1542#endif
   1543
   1544	return pci_register_driver(&pm3fb_driver);
   1545}
   1546
   1547#ifdef MODULE
   1548static void __exit pm3fb_exit(void)
   1549{
   1550	pci_unregister_driver(&pm3fb_driver);
   1551}
   1552
   1553module_exit(pm3fb_exit);
   1554#endif
   1555module_init(pm3fb_init);
   1556
   1557module_param(mode_option, charp, 0);
   1558MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
   1559module_param(noaccel, bool, 0);
   1560MODULE_PARM_DESC(noaccel, "Disable acceleration");
   1561module_param(hwcursor, int, 0644);
   1562MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
   1563			"(1=enable, 0=disable, default=1)");
   1564module_param(nomtrr, bool, 0);
   1565MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
   1566
   1567MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
   1568MODULE_LICENSE("GPL");