summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/riva
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2014-02-13 15:31:38 +0200
committerTomi Valkeinen <tomi.valkeinen@ti.com>2014-04-17 08:10:19 +0300
commitf7018c21350204c4cf628462f229d44d03545254 (patch)
tree408787177164cf51cc06f7aabdb04fcff8d2b6aa /drivers/video/fbdev/riva
parentc26ef3eb3c11274bad1b64498d0a134f85755250 (diff)
downloadlinux-f7018c21350204c4cf628462f229d44d03545254.tar.gz
linux-f7018c21350204c4cf628462f229d44d03545254.tar.bz2
linux-f7018c21350204c4cf628462f229d44d03545254.zip
video: move fbdev to drivers/video/fbdev
The drivers/video directory is a mess. It contains generic video related files, directories for backlight, console, linux logo, lots of fbdev device drivers, fbdev framework files. Make some order into the chaos by creating drivers/video/fbdev directory, and move all fbdev related files there. No functionality is changed, although I guess it is possible that some subtle Makefile build order related issue could be created by this patch. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Acked-by: Rob Clark <robdclark@gmail.com> Acked-by: Jingoo Han <jg1.han@samsung.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/video/fbdev/riva')
-rw-r--r--drivers/video/fbdev/riva/Makefile11
-rw-r--r--drivers/video/fbdev/riva/fbdev.c2230
-rw-r--r--drivers/video/fbdev/riva/nv_driver.c422
-rw-r--r--drivers/video/fbdev/riva/nv_type.h58
-rw-r--r--drivers/video/fbdev/riva/nvreg.h188
-rw-r--r--drivers/video/fbdev/riva/riva_hw.c2268
-rw-r--r--drivers/video/fbdev/riva/riva_hw.h563
-rw-r--r--drivers/video/fbdev/riva/riva_tbl.h1008
-rw-r--r--drivers/video/fbdev/riva/rivafb-i2c.c166
-rw-r--r--drivers/video/fbdev/riva/rivafb.h77
10 files changed, 6991 insertions, 0 deletions
diff --git a/drivers/video/fbdev/riva/Makefile b/drivers/video/fbdev/riva/Makefile
new file mode 100644
index 000000000000..8898c9915b02
--- /dev/null
+++ b/drivers/video/fbdev/riva/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the Riva framebuffer driver
+#
+
+obj-$(CONFIG_FB_RIVA) += rivafb.o
+
+rivafb-objs := fbdev.o riva_hw.o nv_driver.o
+
+ifdef CONFIG_FB_RIVA_I2C
+ rivafb-objs += rivafb-i2c.o
+endif
diff --git a/drivers/video/fbdev/riva/fbdev.c b/drivers/video/fbdev/riva/fbdev.c
new file mode 100644
index 000000000000..8a8d7f060784
--- /dev/null
+++ b/drivers/video/fbdev/riva/fbdev.c
@@ -0,0 +1,2230 @@
+/*
+ * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
+ *
+ * Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
+ *
+ * Copyright 1999-2000 Jeff Garzik
+ *
+ * Contributors:
+ *
+ * Ani Joshi: Lots of debugging and cleanup work, really helped
+ * get the driver going
+ *
+ * Ferenc Bakonyi: Bug fixes, cleanup, modularization
+ *
+ * Jindrich Makovicka: Accel code help, hw cursor, mtrr
+ *
+ * Paul Richards: Bug fixes, updates
+ *
+ * Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven
+ * Includes riva_hw.c from nVidia, see copyright below.
+ * KGI code provided the basis for state storage, init, and mode switching.
+ *
+ * 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.
+ *
+ * Known bugs and issues:
+ * restoring text mode fails
+ * doublescan modes are broken
+ */
+
+#include <linux/module.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>
+#include <linux/backlight.h>
+#include <linux/bitrev.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/machdep.h>
+#include <asm/backlight.h>
+#endif
+
+#include "rivafb.h"
+#include "nvreg.h"
+
+/* version number of this driver */
+#define RIVAFB_VERSION "0.9.5b"
+
+/* ------------------------------------------------------------------------- *
+ *
+ * various helpful macros and constants
+ *
+ * ------------------------------------------------------------------------- */
+#ifdef CONFIG_FB_RIVA_DEBUG
+#define NVTRACE printk
+#else
+#define NVTRACE if(0) printk
+#endif
+
+#define NVTRACE_ENTER(...) NVTRACE("%s START\n", __func__)
+#define NVTRACE_LEAVE(...) NVTRACE("%s END\n", __func__)
+
+#ifdef CONFIG_FB_RIVA_DEBUG
+#define assert(expr) \
+ if(!(expr)) { \
+ printk( "Assertion failed! %s,%s,%s,line=%d\n",\
+ #expr,__FILE__,__func__,__LINE__); \
+ BUG(); \
+ }
+#else
+#define assert(expr)
+#endif
+
+#define PFX "rivafb: "
+
+/* macro that allows you to set overflow bits */
+#define SetBitField(value,from,to) SetBF(to,GetBF(value,from))
+#define SetBit(n) (1<<(n))
+#define Set8Bits(value) ((value)&0xff)
+
+/* HW cursor parameters */
+#define MAX_CURS 32
+
+/* ------------------------------------------------------------------------- *
+ *
+ * prototypes
+ *
+ * ------------------------------------------------------------------------- */
+
+static int rivafb_blank(int blank, struct fb_info *info);
+
+/* ------------------------------------------------------------------------- *
+ *
+ * card identification
+ *
+ * ------------------------------------------------------------------------- */
+
+static struct pci_device_id rivafb_pci_tbl[] = {
+ { PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ // NF2/IGP version, GeForce 4 MX, NV18
+ { PCI_VENDOR_ID_NVIDIA, 0x01f0,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
+
+/* ------------------------------------------------------------------------- *
+ *
+ * global variables
+ *
+ * ------------------------------------------------------------------------- */
+
+/* command line data, set in rivafb_setup() */
+static int flatpanel = -1; /* Autodetect later */
+static int forceCRTC = -1;
+static bool noaccel = 0;
+#ifdef CONFIG_MTRR
+static bool nomtrr = 0;
+#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight = 1;
+#else
+static int backlight = 0;
+#endif
+
+static char *mode_option = NULL;
+static bool strictmode = 0;
+
+static struct fb_fix_screeninfo rivafb_fix = {
+ .type = FB_TYPE_PACKED_PIXELS,
+ .xpanstep = 1,
+ .ypanstep = 1,
+};
+
+static struct fb_var_screeninfo rivafb_default_var = {
+ .xres = 640,
+ .yres = 480,
+ .xres_virtual = 640,
+ .yres_virtual = 480,
+ .bits_per_pixel = 8,
+ .red = {0, 8, 0},
+ .green = {0, 8, 0},
+ .blue = {0, 8, 0},
+ .transp = {0, 0, 0},
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .pixclock = 39721,
+ .left_margin = 40,
+ .right_margin = 24,
+ .upper_margin = 32,
+ .lower_margin = 11,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .vmode = FB_VMODE_NONINTERLACED
+};
+
+/* from GGI */
+static const struct riva_regs reg_template = {
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x01, 0x0F, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CRT */
+ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, /* 0x10 */
+ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, /* 0x40 */
+ },
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, /* GRA */
+ 0xFF},
+ {0x03, 0x01, 0x0F, 0x00, 0x0E}, /* SEQ */
+ 0xEB /* MISC */
+};
+
+/*
+ * Backlight control
+ */
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
+#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
+
+static int riva_bl_get_level_brightness(struct riva_par *par,
+ int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int nlevel;
+
+ /* Get and convert the value */
+ /* No locking on bl_curve since accessing a single value */
+ nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
+
+ if (nlevel < 0)
+ nlevel = 0;
+ else if (nlevel < MIN_LEVEL)
+ nlevel = MIN_LEVEL;
+ else if (nlevel > MAX_LEVEL)
+ nlevel = MAX_LEVEL;
+
+ return nlevel;
+}
+
+static int riva_bl_update_status(struct backlight_device *bd)
+{
+ struct riva_par *par = bl_get_data(bd);
+ U032 tmp_pcrt, tmp_pmc;
+ int level;
+
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props.brightness;
+
+ tmp_pmc = NV_RD32(par->riva.PMC, 0x10F0) & 0x0000FFFF;
+ tmp_pcrt = NV_RD32(par->riva.PCRTC0, 0x081C) & 0xFFFFFFFC;
+ if(level > 0) {
+ tmp_pcrt |= 0x1;
+ tmp_pmc |= (1 << 31); /* backlight bit */
+ tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
+ }
+ NV_WR32(par->riva.PCRTC0, 0x081C, tmp_pcrt);
+ NV_WR32(par->riva.PMC, 0x10F0, tmp_pmc);
+
+ return 0;
+}
+
+static int riva_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static const struct backlight_ops riva_bl_ops = {
+ .get_brightness = riva_bl_get_brightness,
+ .update_status = riva_bl_update_status,
+};
+
+static void riva_bl_init(struct riva_par *par)
+{
+ struct backlight_properties props;
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+ if (!par->FlatPanel)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!machine_is(powermac) ||
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "rivabl%d", info->node);
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd = backlight_device_register(name, info->dev, par, &riva_bl_ops,
+ &props);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk(KERN_WARNING "riva: Backlight registration failed\n");
+ goto error;
+ }
+
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ MIN_LEVEL * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ FB_BACKLIGHT_MAX);
+
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
+
+ printk("riva: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void riva_bl_exit(struct fb_info *info)
+{
+ struct backlight_device *bd = info->bl_dev;
+
+ backlight_device_unregister(bd);
+ printk("riva: Backlight unloaded\n");
+}
+#else
+static inline void riva_bl_init(struct riva_par *par) {}
+static inline void riva_bl_exit(struct fb_info *info) {}
+#endif /* CONFIG_FB_RIVA_BACKLIGHT */
+
+/* ------------------------------------------------------------------------- *
+ *
+ * MMIO access macros
+ *
+ * ------------------------------------------------------------------------- */
+
+static inline void CRTCout(struct riva_par *par, unsigned char index,
+ unsigned char val)
+{
+ VGA_WR08(par->riva.PCIO, 0x3d4, index);
+ VGA_WR08(par->riva.PCIO, 0x3d5, val);
+}
+
+static inline unsigned char CRTCin(struct riva_par *par,
+ unsigned char index)
+{
+ VGA_WR08(par->riva.PCIO, 0x3d4, index);
+ return (VGA_RD08(par->riva.PCIO, 0x3d5));
+}
+
+static inline void GRAout(struct riva_par *par, unsigned char index,
+ unsigned char val)
+{
+ VGA_WR08(par->riva.PVIO, 0x3ce, index);
+ VGA_WR08(par->riva.PVIO, 0x3cf, val);
+}
+
+static inline unsigned char GRAin(struct riva_par *par,
+ unsigned char index)
+{
+ VGA_WR08(par->riva.PVIO, 0x3ce, index);
+ return (VGA_RD08(par->riva.PVIO, 0x3cf));
+}
+
+static inline void SEQout(struct riva_par *par, unsigned char index,
+ unsigned char val)
+{
+ VGA_WR08(par->riva.PVIO, 0x3c4, index);
+ VGA_WR08(par->riva.PVIO, 0x3c5, val);
+}
+
+static inline unsigned char SEQin(struct riva_par *par,
+ unsigned char index)
+{
+ VGA_WR08(par->riva.PVIO, 0x3c4, index);
+ return (VGA_RD08(par->riva.PVIO, 0x3c5));
+}
+
+static inline void ATTRout(struct riva_par *par, unsigned char index,
+ unsigned char val)
+{
+ VGA_WR08(par->riva.PCIO, 0x3c0, index);
+ VGA_WR08(par->riva.PCIO, 0x3c0, val);
+}
+
+static inline unsigned char ATTRin(struct riva_par *par,
+ unsigned char index)
+{
+ VGA_WR08(par->riva.PCIO, 0x3c0, index);
+ return (VGA_RD08(par->riva.PCIO, 0x3c1));
+}
+
+static inline void MISCout(struct riva_par *par, unsigned char val)
+{
+ VGA_WR08(par->riva.PVIO, 0x3c2, val);
+}
+
+static inline unsigned char MISCin(struct riva_par *par)
+{
+ return (VGA_RD08(par->riva.PVIO, 0x3cc));
+}
+
+static inline void reverse_order(u32 *l)
+{
+ u8 *a = (u8 *)l;
+ a[0] = bitrev8(a[0]);
+ a[1] = bitrev8(a[1]);
+ a[2] = bitrev8(a[2]);
+ a[3] = bitrev8(a[3]);
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * cursor stuff
+ *
+ * ------------------------------------------------------------------------- */
+
+/**
+ * rivafb_load_cursor_image - load cursor image to hardware
+ * @data: address to monochrome bitmap (1 = foreground color, 0 = background)
+ * @par: pointer to private data
+ * @w: width of cursor image in pixels
+ * @h: height of cursor image in scanlines
+ * @bg: background color (ARGB1555) - alpha bit determines opacity
+ * @fg: foreground color (ARGB1555)
+ *
+ * DESCRIPTiON:
+ * Loads cursor image based on a monochrome source and mask bitmap. The
+ * image bits determines the color of the pixel, 0 for background, 1 for
+ * foreground. Only the affected region (as determined by @w and @h
+ * parameters) will be updated.
+ *
+ * CALLED FROM:
+ * rivafb_cursor()
+ */
+static void rivafb_load_cursor_image(struct riva_par *par, u8 *data8,
+ u16 bg, u16 fg, u32 w, u32 h)
+{
+ int i, j, k = 0;
+ u32 b, tmp;
+ u32 *data = (u32 *)data8;
+ bg = le16_to_cpu(bg);
+ fg = le16_to_cpu(fg);
+
+ w = (w + 1) & ~1;
+
+ for (i = 0; i < h; i++) {
+ b = *data++;
+ reverse_order(&b);
+
+ for (j = 0; j < w/2; j++) {
+ tmp = 0;
+#if defined (__BIG_ENDIAN)
+ tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
+ b <<= 1;
+ tmp |= (b & (1 << 31)) ? fg : bg;
+ b <<= 1;
+#else
+ tmp = (b & 1) ? fg : bg;
+ b >>= 1;
+ tmp |= (b & 1) ? fg << 16 : bg << 16;
+ b >>= 1;
+#endif
+ writel(tmp, &par->riva.CURSOR[k++]);
+ }
+ k += (MAX_CURS - w)/2;
+ }
+}
+
+/* ------------------------------------------------------------------------- *
+ *
+ * general utility functions
+ *
+ * ------------------------------------------------------------------------- */
+
+/**
+ * riva_wclut - set CLUT entry
+ * @chip: pointer to RIVA_HW_INST object
+ * @regnum: register number
+ * @red: red component
+ * @green: green component
+ * @blue: blue component
+ *
+ * DESCRIPTION:
+ * Sets color register @regnum.
+ *
+ * CALLED FROM:
+ * rivafb_setcolreg()
+ */
+static void riva_wclut(RIVA_HW_INST *chip,
+ unsigned char regnum, unsigned char red,
+ unsigned char green, unsigned char blue)
+{
+ VGA_WR08(chip->PDIO, 0x3c8, regnum);
+ VGA_WR08(chip->PDIO, 0x3c9, red);
+ VGA_WR08(chip->PDIO, 0x3c9, green);
+ VGA_WR08(chip->PDIO, 0x3c9, blue);
+}
+
+/**
+ * riva_rclut - read fromCLUT register
+ * @chip: pointer to RIVA_HW_INST object
+ * @regnum: register number
+ * @red: red component
+ * @green: green component
+ * @blue: blue component
+ *
+ * DESCRIPTION:
+ * Reads red, green, and blue from color register @regnum.
+ *
+ * CALLED FROM:
+ * rivafb_setcolreg()
+ */
+static void riva_rclut(RIVA_HW_INST *chip,
+ unsigned char regnum, unsigned char *red,
+ unsigned char *green, unsigned char *blue)
+{
+
+ VGA_WR08(chip->PDIO, 0x3c7, regnum);
+ *red = VGA_RD08(chip->PDIO, 0x3c9);
+ *green = VGA_RD08(chip->PDIO, 0x3c9);
+ *blue = VGA_RD08(chip->PDIO, 0x3c9);
+}
+
+/**
+ * riva_save_state - saves current chip state
+ * @par: pointer to riva_par object containing info for current riva board
+ * @regs: pointer to riva_regs object
+ *
+ * DESCRIPTION:
+ * Saves current chip state to @regs.
+ *
+ * CALLED FROM:
+ * rivafb_probe()
+ */
+/* from GGI */
+static void riva_save_state(struct riva_par *par, struct riva_regs *regs)
+{
+ int i;
+
+ NVTRACE_ENTER();
+ par->riva.LockUnlock(&par->riva, 0);
+
+ par->riva.UnloadStateExt(&par->riva, &regs->ext);
+
+ regs->misc_output = MISCin(par);
+
+ for (i = 0; i < NUM_CRT_REGS; i++)
+ regs->crtc[i] = CRTCin(par, i);
+
+ for (i = 0; i < NUM_ATC_REGS; i++)
+ regs->attr[i] = ATTRin(par, i);
+
+ for (i = 0; i < NUM_GRC_REGS; i++)
+ regs->gra[i] = GRAin(par, i);
+
+ for (i = 0; i < NUM_SEQ_REGS; i++)
+ regs->seq[i] = SEQin(par, i);
+ NVTRACE_LEAVE();
+}
+
+/**
+ * riva_load_state - loads current chip state
+ * @par: pointer to riva_par object containing info for current riva board
+ * @regs: pointer to riva_regs object
+ *
+ * DESCRIPTION:
+ * Loads chip state from @regs.
+ *
+ * CALLED FROM:
+ * riva_load_video_mode()
+ * rivafb_probe()
+ * rivafb_remove()
+ */
+/* from GGI */
+static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
+{
+ RIVA_HW_STATE *state = &regs->ext;
+ int i;
+
+ NVTRACE_ENTER();
+ CRTCout(par, 0x11, 0x00);
+
+ par->riva.LockUnlock(&par->riva, 0);
+
+ par->riva.LoadStateExt(&par->riva, state);
+
+ MISCout(par, regs->misc_output);
+
+ for (i = 0; i < NUM_CRT_REGS; i++) {
+ switch (i) {
+ case 0x19:
+ case 0x20 ... 0x40:
+ break;
+ default:
+ CRTCout(par, i, regs->crtc[i]);
+ }
+ }
+
+ for (i = 0; i < NUM_ATC_REGS; i++)
+ ATTRout(par, i, regs->attr[i]);
+
+ for (i = 0; i < NUM_GRC_REGS; i++)
+ GRAout(par, i, regs->gra[i]);
+
+ for (i = 0; i < NUM_SEQ_REGS; i++)
+ SEQout(par, i, regs->seq[i]);
+ NVTRACE_LEAVE();
+}
+
+/**
+ * riva_load_video_mode - calculate timings
+ * @info: pointer to fb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Calculate some timings and then send em off to riva_load_state().
+ *
+ * CALLED FROM:
+ * rivafb_set_par()
+ */
+static int riva_load_video_mode(struct fb_info *info)
+{
+ int bpp, width, hDisplaySize, hDisplay, hStart,
+ hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
+ int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
+ int rc;
+ struct riva_par *par = info->par;
+ struct riva_regs newmode;
+
+ NVTRACE_ENTER();
+ /* time to calculate */
+ rivafb_blank(FB_BLANK_NORMAL, info);
+
+ bpp = info->var.bits_per_pixel;
+ if (bpp == 16 && info->var.green.length == 5)
+ bpp = 15;
+ width = info->var.xres_virtual;
+ hDisplaySize = info->var.xres;
+ hDisplay = (hDisplaySize / 8) - 1;
+ hStart = (hDisplaySize + info->var.right_margin) / 8 - 1;
+ hEnd = (hDisplaySize + info->var.right_margin +
+ info->var.hsync_len) / 8 - 1;
+ hTotal = (hDisplaySize + info->var.right_margin +
+ info->var.hsync_len + info->var.left_margin) / 8 - 5;
+ hBlankStart = hDisplay;
+ hBlankEnd = hTotal + 4;
+
+ height = info->var.yres_virtual;
+ vDisplay = info->var.yres - 1;
+ vStart = info->var.yres + info->var.lower_margin - 1;
+ vEnd = info->var.yres + info->var.lower_margin +
+ info->var.vsync_len - 1;
+ vTotal = info->var.yres + info->var.lower_margin +
+ info->var.vsync_len + info->var.upper_margin + 2;
+ vBlankStart = vDisplay;
+ vBlankEnd = vTotal + 1;
+ dotClock = 1000000000 / info->var.pixclock;
+
+ memcpy(&newmode, &reg_template, sizeof(struct riva_regs));
+
+ if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+ vTotal |= 1;
+
+ if (par->FlatPanel) {
+ vStart = vTotal - 3;
+ vEnd = vTotal - 2;
+ vBlankStart = vStart;
+ hStart = hTotal - 3;
+ hEnd = hTotal - 2;
+ hBlankEnd = hTotal + 4;
+ }
+
+ newmode.crtc[0x0] = Set8Bits (hTotal);
+ newmode.crtc[0x1] = Set8Bits (hDisplay);
+ newmode.crtc[0x2] = Set8Bits (hBlankStart);
+ newmode.crtc[0x3] = SetBitField (hBlankEnd, 4: 0, 4:0) | SetBit (7);
+ newmode.crtc[0x4] = Set8Bits (hStart);
+ newmode.crtc[0x5] = SetBitField (hBlankEnd, 5: 5, 7:7)
+ | SetBitField (hEnd, 4: 0, 4:0);
+ newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
+ newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
+ | SetBitField (vDisplay, 8: 8, 1:1)
+ | SetBitField (vStart, 8: 8, 2:2)
+ | SetBitField (vBlankStart, 8: 8, 3:3)
+ | SetBit (4)
+ | SetBitField (vTotal, 9: 9, 5:5)
+ | SetBitField (vDisplay, 9: 9, 6:6)
+ | SetBitField (vStart, 9: 9, 7:7);
+ newmode.crtc[0x9] = SetBitField (vBlankStart, 9: 9, 5:5)
+ | SetBit (6);
+ newmode.crtc[0x10] = Set8Bits (vStart);
+ newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
+ | SetBit (5);
+ newmode.crtc[0x12] = Set8Bits (vDisplay);
+ newmode.crtc[0x13] = (width / 8) * ((bpp + 1) / 8);
+ newmode.crtc[0x15] = Set8Bits (vBlankStart);
+ newmode.crtc[0x16] = Set8Bits (vBlankEnd);
+
+ newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4)
+ | SetBitField(vBlankStart,10:10,3:3)
+ | SetBitField(vStart,10:10,2:2)
+ | SetBitField(vDisplay,10:10,1:1)
+ | SetBitField(vTotal,10:10,0:0);
+ newmode.ext.horiz = SetBitField(hTotal,8:8,0:0)
+ | SetBitField(hDisplay,8:8,1:1)
+ | SetBitField(hBlankStart,8:8,2:2)
+ | SetBitField(hStart,8:8,3:3);
+ newmode.ext.extra = SetBitField(vTotal,11:11,0:0)
+ | SetBitField(vDisplay,11:11,2:2)
+ | SetBitField(vStart,11:11,4:4)
+ | SetBitField(vBlankStart,11:11,6:6);
+
+ if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ int tmp = (hTotal >> 1) & ~1;
+ newmode.ext.interlace = Set8Bits(tmp);
+ newmode.ext.horiz |= SetBitField(tmp, 8:8,4:4);
+ } else
+ newmode.ext.interlace = 0xff; /* interlace off */
+
+ if (par->riva.Architecture >= NV_ARCH_10)
+ par->riva.CURSOR = (U032 __iomem *)(info->screen_base + par->riva.CursorStart);
+
+ if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ newmode.misc_output &= ~0x40;
+ else
+ newmode.misc_output |= 0x40;
+ if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ newmode.misc_output &= ~0x80;
+ else
+ newmode.misc_output |= 0x80;
+
+ rc = CalcStateExt(&par->riva, &newmode.ext, bpp, width,
+ hDisplaySize, height, dotClock);
+ if (rc)
+ goto out;
+
+ newmode.ext.scale = NV_RD32(par->riva.PRAMDAC, 0x00000848) &
+ 0xfff000ff;
+ if (par->FlatPanel == 1) {
+ newmode.ext.pixel |= (1 << 7);
+ newmode.ext.scale |= (1 << 8);
+ }
+ if (par->SecondCRTC) {
+ newmode.ext.head = NV_RD32(par->riva.PCRTC0, 0x00000860) &
+ ~0x00001000;
+ newmode.ext.head2 = NV_RD32(par->riva.PCRTC0, 0x00002860) |
+ 0x00001000;
+ newmode.ext.crtcOwner = 3;
+ newmode.ext.pllsel |= 0x20000800;
+ newmode.ext.vpll2 = newmode.ext.vpll;
+ } else if (par->riva.twoHeads) {
+ newmode.ext.head = NV_RD32(par->riva.PCRTC0, 0x00000860) |
+ 0x00001000;
+ newmode.ext.head2 = NV_RD32(par->riva.PCRTC0, 0x00002860) &
+ ~0x00001000;
+ newmode.ext.crtcOwner = 0;
+ newmode.ext.vpll2 = NV_RD32(par->riva.PRAMDAC0, 0x00000520);
+ }
+ if (par->FlatPanel == 1) {
+ newmode.ext.pixel |= (1 << 7);
+ newmode.ext.scale |= (1 << 8);
+ }
+ newmode.ext.cursorConfig = 0x02000100;
+ par->current_state = newmode;
+ riva_load_state(par, &par->current_state);
+ par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */
+
+out:
+ rivafb_blank(FB_BLANK_UNBLANK, info);
+ NVTRACE_LEAVE();
+
+ return rc;
+}
+
+static void riva_update_var(struct fb_var_screeninfo *var,
+ const struct fb_videomode *modedb)
+{
+ NVTRACE_ENTER();
+ var->xres = var->xres_virtual = modedb->xres;
+ var->yres = modedb->yres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+ var->xoffset = var->yoffset = 0;
+ var->pixclock = modedb->pixclock;
+ var->left_margin = modedb->left_margin;
+ var->right_margin = modedb->right_margin;
+ var->upper_margin = modedb->upper_margin;
+ var->lower_margin = modedb->lower_margin;
+ var->hsync_len = modedb->hsync_len;
+ var->vsync_len = modedb->vsync_len;
+ var->sync = modedb->sync;
+ var->vmode = modedb->vmode;
+ NVTRACE_LEAVE();
+}
+
+/**
+ * rivafb_do_maximize -
+ * @info: pointer to fb_info object containing info for current riva board
+ * @var:
+ * @nom:
+ * @den:
+ *
+ * DESCRIPTION:
+ * .
+ *
+ * RETURNS:
+ * -EINVAL on failure, 0 on success
+ *
+ *
+ * CALLED FROM:
+ * rivafb_check_var()
+ */
+static int rivafb_do_maximize(struct fb_info *info,
+ struct fb_var_screeninfo *var,
+ int nom, int den)
+{
+ static struct {
+ int xres, yres;
+ } modes[] = {
+ {1600, 1280},
+ {1280, 1024},
+ {1024, 768},
+ {800, 600},
+ {640, 480},
+ {-1, -1}
+ };
+ int i;
+
+ NVTRACE_ENTER();
+ /* use highest possible virtual resolution */
+ if (var->xres_virtual == -1 && var->yres_virtual == -1) {
+ printk(KERN_WARNING PFX
+ "using maximum available virtual resolution\n");
+ for (i = 0; modes[i].xres != -1; i++) {
+ if (modes[i].xres * nom / den * modes[i].yres <
+ info->fix.smem_len)
+ break;
+ }
+ if (modes[i].xres == -1) {
+ printk(KERN_ERR PFX
+ "could not find a virtual resolution that fits into video memory!!\n");
+ NVTRACE("EXIT - EINVAL error\n");
+ return -EINVAL;
+ }
+ var->xres_virtual = modes[i].xres;
+ var->yres_virtual = modes[i].yres;
+
+ printk(KERN_INFO PFX
+ "virtual resolution set to maximum of %dx%d\n",
+ var->xres_virtual, var->yres_virtual);
+ } else if (var->xres_virtual == -1) {
+ var->xres_virtual = (info->fix.smem_len * den /
+ (nom * var->yres_virtual)) & ~15;
+ printk(KERN_WARNING PFX
+ "setting virtual X resolution to %d\n", var->xres_virtual);
+ } else if (var->yres_virtual == -1) {
+ var->xres_virtual = (var->xres_virtual + 15) & ~15;
+ var->yres_virtual = info->fix.smem_len * den /
+ (nom * var->xres_virtual);
+ printk(KERN_WARNING PFX
+ "setting virtual Y resolution to %d\n", var->yres_virtual);
+ } else {
+ var->xres_virtual = (var->xres_virtual + 15) & ~15;
+ if (var->xres_virtual * nom / den * var->yres_virtual > info->fix.smem_len) {
+ printk(KERN_ERR PFX
+ "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ NVTRACE("EXIT - EINVAL error\n");
+ return -EINVAL;
+ }
+ }
+
+ if (var->xres_virtual * nom / den >= 8192) {
+ printk(KERN_WARNING PFX
+ "virtual X resolution (%d) is too high, lowering to %d\n",
+ var->xres_virtual, 8192 * den / nom - 16);
+ var->xres_virtual = 8192 * den / nom - 16;
+ }
+
+ if (var->xres_virtual < var->xres) {
+ printk(KERN_ERR PFX
+ "virtual X resolution (%d) is smaller than real\n", var->xres_virtual);
+ return -EINVAL;
+ }
+
+ if (var->yres_virtual < var->yres) {
+ printk(KERN_ERR PFX
+ "virtual Y resolution (%d) is smaller than real\n", var->yres_virtual);
+ return -EINVAL;