/drivers/video/pm2fb.c
C | 1860 lines | 1426 code | 192 blank | 242 comment | 217 complexity | 6c3a8dd1c9c82b7946437c3825fcfaeb MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*
- * Permedia2 framebuffer driver.
- *
- * 2.5/2.6 driver:
- * Copyright (c) 2003 Jim Hague (jim.hague@acm.org)
- *
- * based on 2.4 driver:
- * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
- * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
- *
- * and additional input from James Simmon's port of Hannu Mallat's tdfx
- * driver.
- *
- * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I
- * have no access to other pm2fb implementations. Sparc (and thus
- * hopefully other big-endian) devices now work, thanks to a lot of
- * testing work by Ron Murray. I have no access to CVision hardware,
- * and therefore for now I am omitting the CVision code.
- *
- * Multiple boards support has been on the TODO list for ages.
- * Don't expect this to change.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
- *
- */
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/fb.h>
- #include <linux/init.h>
- #include <linux/pci.h>
- #ifdef CONFIG_MTRR
- #include <asm/mtrr.h>
- #endif
- #include <video/permedia2.h>
- #include <video/cvisionppc.h>
- #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
- #error "The endianness of the target host has not been defined."
- #endif
- #if !defined(CONFIG_PCI)
- #error "Only generic PCI cards supported."
- #endif
- #undef PM2FB_MASTER_DEBUG
- #ifdef PM2FB_MASTER_DEBUG
- #define DPRINTK(a, b...) \
- printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b)
- #else
- #define DPRINTK(a, b...)
- #endif
- #define PM2_PIXMAP_SIZE (1600 * 4)
- /*
- * Driver data
- */
- static int hwcursor = 1;
- static char *mode_option __devinitdata;
- /*
- * The XFree GLINT driver will (I think to implement hardware cursor
- * support on TVP4010 and similar where there is no RAMDAC - see
- * comment in set_video) always request +ve sync regardless of what
- * the mode requires. This screws me because I have a Sun
- * fixed-frequency monitor which absolutely has to have -ve sync. So
- * these flags allow the user to specify that requests for +ve sync
- * should be silently turned in -ve sync.
- */
- static int lowhsync;
- static int lowvsync;
- static int noaccel __devinitdata;
- /* mtrr option */
- #ifdef CONFIG_MTRR
- static int nomtrr __devinitdata;
- #endif
- /*
- * The hardware state of the graphics card that isn't part of the
- * screeninfo.
- */
- struct pm2fb_par
- {
- pm2type_t type; /* Board type */
- unsigned char __iomem *v_regs;/* virtual address of p_regs */
- u32 memclock; /* memclock */
- u32 video; /* video flags before blanking */
- u32 mem_config; /* MemConfig reg at probe */
- u32 mem_control; /* MemControl reg at probe */
- u32 boot_address; /* BootAddress reg at probe */
- u32 palette[16];
- int mtrr_handle;
- };
- /*
- * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
- * if we don't use modedb.
- */
- static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
- .id = "",
- .type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_PSEUDOCOLOR,
- .xpanstep = 1,
- .ypanstep = 1,
- .ywrapstep = 0,
- .accel = FB_ACCEL_3DLABS_PERMEDIA2,
- };
- /*
- * Default video mode. In case the modedb doesn't work.
- */
- static struct fb_var_screeninfo pm2fb_var __devinitdata = {
- /* "640x480, 8 bpp @ 60 Hz */
- .xres = 640,
- .yres = 480,
- .xres_virtual = 640,
- .yres_virtual = 480,
- .bits_per_pixel = 8,
- .red = {0, 8, 0},
- .blue = {0, 8, 0},
- .green = {0, 8, 0},
- .activate = FB_ACTIVATE_NOW,
- .height = -1,
- .width = -1,
- .accel_flags = 0,
- .pixclock = 39721,
- .left_margin = 40,
- .right_margin = 24,
- .upper_margin = 32,
- .lower_margin = 11,
- .hsync_len = 96,
- .vsync_len = 2,
- .vmode = FB_VMODE_NONINTERLACED
- };
- /*
- * Utility functions
- */
- static inline u32 pm2_RD(struct pm2fb_par *p, s32 off)
- {
- return fb_readl(p->v_regs + off);
- }
- static inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v)
- {
- fb_writel(v, p->v_regs + off);
- }
- static inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx)
- {
- pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
- mb();
- return pm2_RD(p, PM2R_RD_INDEXED_DATA);
- }
- static inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx)
- {
- pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
- mb();
- return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
- }
- static inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
- {
- pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
- wmb();
- pm2_WR(p, PM2R_RD_INDEXED_DATA, v);
- wmb();
- }
- static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
- {
- pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
- wmb();
- pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
- wmb();
- }
- #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
- #define WAIT_FIFO(p, a)
- #else
- static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a)
- {
- while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a)
- cpu_relax();
- }
- #endif
- /*
- * partial products for the supported horizontal resolutions.
- */
- #define PACKPP(p0, p1, p2) (((p2) << 6) | ((p1) << 3) | (p0))
- static const struct {
- u16 width;
- u16 pp;
- } pp_table[] = {
- { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) },
- { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) },
- { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) },
- { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) },
- { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) },
- { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) },
- { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) },
- { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) },
- { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) },
- { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) },
- { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) },
- { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) },
- { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) },
- { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) },
- { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) },
- { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) },
- { 0, 0 } };
- static u32 partprod(u32 xres)
- {
- int i;
- for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)
- ;
- if (pp_table[i].width == 0)
- DPRINTK("invalid width %u\n", xres);
- return pp_table[i].pp;
- }
- static u32 to3264(u32 timing, int bpp, int is64)
- {
- switch (bpp) {
- case 24:
- timing *= 3;
- case 8:
- timing >>= 1;
- case 16:
- timing >>= 1;
- case 32:
-