aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/savage
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/video/savage
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/video/savage')
-rw-r--r--drivers/video/savage/Makefile9
-rw-r--r--drivers/video/savage/savagefb-i2c.c282
-rw-r--r--drivers/video/savage/savagefb.h354
-rw-r--r--drivers/video/savage/savagefb_accel.c136
-rw-r--r--drivers/video/savage/savagefb_driver.c2279
5 files changed, 3060 insertions, 0 deletions
diff --git a/drivers/video/savage/Makefile b/drivers/video/savage/Makefile
new file mode 100644
index 00000000000..e09770fff8e
--- /dev/null
+++ b/drivers/video/savage/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the S3 Savage framebuffer driver
+#
+
+obj-$(CONFIG_FB_SAVAGE) += savagefb.o
+
+savagefb-y += savagefb_driver.o
+savagefb-$(CONFIG_FB_SAVAGE_I2C) += savagefb-i2c.o
+savagefb-$(CONFIG_FB_SAVAGE_ACCEL) += savagefb_accel.o
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
new file mode 100644
index 00000000000..024a0cecff1
--- /dev/null
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -0,0 +1,282 @@
+/*
+ * linux/drivers/video/savage/savagefb-i2c.c - S3 Savage DDC2
+ *
+ * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
+ *
+ * Based partly on rivafb-i2c.c
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+#include "savagefb.h"
+
+#define SAVAGE_DDC 0x50
+
+#define VGA_CR_IX 0x3d4
+#define VGA_CR_DATA 0x3d5
+
+#define CR_SERIAL1 0xa0 /* I2C serial communications interface */
+#define MM_SERIAL1 0xff20
+#define CR_SERIAL2 0xb1 /* DDC2 monitor communications interface */
+
+/* based on vt8365 documentation */
+#define PROSAVAGE_I2C_ENAB 0x10
+#define PROSAVAGE_I2C_SCL_OUT 0x01
+#define PROSAVAGE_I2C_SDA_OUT 0x02
+#define PROSAVAGE_I2C_SCL_IN 0x04
+#define PROSAVAGE_I2C_SDA_IN 0x08
+
+#define SAVAGE4_I2C_ENAB 0x00000020
+#define SAVAGE4_I2C_SCL_OUT 0x00000001
+#define SAVAGE4_I2C_SDA_OUT 0x00000002
+#define SAVAGE4_I2C_SCL_IN 0x00000008
+#define SAVAGE4_I2C_SDA_IN 0x00000010
+
+#define SET_CR_IX(base, val) writeb((val), base + 0x8000 + VGA_CR_IX)
+#define SET_CR_DATA(base, val) writeb((val), base + 0x8000 + VGA_CR_DATA)
+#define GET_CR_DATA(base) readb(base + 0x8000 + VGA_CR_DATA)
+
+static void savage4_gpio_setscl(void *data, int val)
+{
+ struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+ unsigned int r;
+
+ r = readl(chan->ioaddr + chan->reg);
+ if(val)
+ r |= SAVAGE4_I2C_SCL_OUT;
+ else
+ r &= ~SAVAGE4_I2C_SCL_OUT;
+ writel(r, chan->ioaddr + chan->reg);
+ readl(chan->ioaddr + chan->reg); /* flush posted write */
+}
+
+static void savage4_gpio_setsda(void *data, int val)
+{
+ struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+ unsigned int r;
+ r = readl(chan->ioaddr + chan->reg);
+ if(val)
+ r |= SAVAGE4_I2C_SDA_OUT;
+ else
+ r &= ~SAVAGE4_I2C_SDA_OUT;
+ writel(r, chan->ioaddr + chan->reg);
+ readl(chan->ioaddr + chan->reg); /* flush posted write */
+}
+
+static int savage4_gpio_getscl(void *data)
+{
+ struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+ return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SCL_IN));
+}
+
+static int savage4_gpio_getsda(void *data)
+{
+ struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+ return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SDA_IN));
+}
+
+static void prosavage_gpio_setscl(void* data, int val)
+{
+ struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+ u32 r;
+
+ SET_CR_IX(chan->ioaddr, chan->reg);
+ r = GET_CR_DATA(chan->ioaddr);
+ r |= PROSAVAGE_I2C_ENAB;
+ if (val) {
+ r |= PROSAVAGE_I2C_SCL_OUT;
+ } else {
+ r &= ~PROSAVAGE_I2C_SCL_OUT;
+ }
+ SET_CR_DATA(chan->ioaddr, r);
+}
+
+static void prosavage_gpio_setsda(void* data, int val)
+{
+ struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+ unsigned int r;
+
+ SET_CR_IX(chan->ioaddr, chan->reg);
+ r = GET_CR_DATA(chan->ioaddr);
+ r |= PROSAVAGE_I2C_ENAB;
+ if (val) {
+ r |= PROSAVAGE_I2C_SDA_OUT;
+ } else {
+ r &= ~PROSAVAGE_I2C_SDA_OUT;
+ }
+ SET_CR_DATA(chan->ioaddr, r);
+}
+
+static int prosavage_gpio_getscl(void* data)
+{
+ struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+ SET_CR_IX(chan->ioaddr, chan->reg);
+ return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SCL_IN));
+}
+
+static int prosavage_gpio_getsda(void* data)
+{
+ struct savagefb_i2c_chan *chan = (struct savagefb_i2c_chan *)data;
+
+ SET_CR_IX(chan->ioaddr, chan->reg);
+ return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SDA_IN));
+}
+
+#define I2C_ALGO_SAVAGE 0x0f0000
+static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
+ const char *name)
+{
+ int (*add_bus)(struct i2c_adapter *) = symbol_get(i2c_bit_add_bus);
+ int rc = 0;
+
+ if (add_bus && chan->par) {
+ strcpy(chan->adapter.name, name);
+ chan->adapter.owner = THIS_MODULE;
+ chan->adapter.id = I2C_ALGO_SAVAGE;
+ chan->adapter.algo_data = &chan->algo;
+ chan->adapter.dev.parent = &chan->par->pcidev->dev;
+ chan->algo.udelay = 40;
+ chan->algo.mdelay = 5;
+ chan->algo.timeout = 20;
+ chan->algo.data = chan;
+
+ i2c_set_adapdata(&chan->adapter, chan);
+
+ /* Raise SCL and SDA */
+ chan->algo.setsda(chan, 1);
+ chan->algo.setscl(chan, 1);
+ udelay(20);
+
+ rc = add_bus(&chan->adapter);
+
+ if (rc == 0)
+ dev_dbg(&chan->par->pcidev->dev,
+ "I2C bus %s registered.\n", name);
+ else
+ dev_warn(&chan->par->pcidev->dev,
+ "Failed to register I2C bus %s.\n", name);
+
+ symbol_put(i2c_bit_add_bus);
+ } else
+ chan->par = NULL;
+
+ return rc;
+}
+
+void savagefb_create_i2c_busses(struct fb_info *info)
+{
+ struct savagefb_par *par = (struct savagefb_par *)info->par;
+ par->chan.par = par;
+
+ switch(info->fix.accel) {
+ case FB_ACCEL_PROSAVAGE_DDRK:
+ case FB_ACCEL_PROSAVAGE_PM:
+ par->chan.reg = CR_SERIAL2;
+ par->chan.ioaddr = par->mmio.vbase;
+ par->chan.algo.setsda = prosavage_gpio_setsda;
+ par->chan.algo.setscl = prosavage_gpio_setscl;
+ par->chan.algo.getsda = prosavage_gpio_getsda;
+ par->chan.algo.getscl = prosavage_gpio_getscl;
+ break;
+ case FB_ACCEL_SAVAGE4:
+ par->chan.reg = 0xff20;
+ par->chan.ioaddr = par->mmio.vbase;
+ par->chan.algo.setsda = savage4_gpio_setsda;
+ par->chan.algo.setscl = savage4_gpio_setscl;
+ par->chan.algo.getsda = savage4_gpio_getsda;
+ par->chan.algo.getscl = savage4_gpio_getscl;
+ break;
+ default:
+ par->chan.par = NULL;
+ }
+
+ savage_setup_i2c_bus(&par->chan, "SAVAGE DDC2");
+}
+
+void savagefb_delete_i2c_busses(struct fb_info *info)
+{
+ struct savagefb_par *par = (struct savagefb_par *)info->par;
+ int (*del_bus)(struct i2c_adapter *) =
+ symbol_get(i2c_bit_del_bus);
+
+ if (del_bus && par->chan.par) {
+ del_bus(&par->chan.adapter);
+ symbol_put(i2c_bit_del_bus);
+ }
+
+ par->chan.par = NULL;
+}
+
+static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan)
+{
+ u8 start = 0x0;
+ int (*transfer)(struct i2c_adapter *, struct i2c_msg *, int) =
+ symbol_get(i2c_transfer);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = SAVAGE_DDC,
+ .len = 1,
+ .buf = &start,
+ }, {
+ .addr = SAVAGE_DDC,
+ .flags = I2C_M_RD,
+ .len = EDID_LENGTH,
+ },
+ };
+ u8 *buf = NULL;
+
+ if (transfer && chan->par) {
+ buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+
+ if (buf) {
+ msgs[1].buf = buf;
+
+ if (transfer(&chan->adapter, msgs, 2) != 2) {
+ dev_dbg(&chan->par->pcidev->dev,
+ "Unable to read EDID block.\n");
+ kfree(buf);
+ buf = NULL;
+ }
+ }
+
+ symbol_put(i2c_transfer);
+ }
+
+ return buf;
+}
+
+int savagefb_probe_i2c_connector(struct savagefb_par *par, u8 **out_edid)
+{
+ u8 *edid = NULL;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ /* Do the real work */
+ edid = savage_do_probe_i2c_edid(&par->chan);
+ if (edid)
+ break;
+ }
+ if (out_edid)
+ *out_edid = edid;
+ if (!edid)
+ return 1;
+
+ return 0;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
new file mode 100644
index 00000000000..8594b1e42d7
--- /dev/null
+++ b/drivers/video/savage/savagefb.h
@@ -0,0 +1,354 @@
+/*
+ * linux/drivers/video/savagefb.h -- S3 Savage Framebuffer Driver
+ *
+ * Copyright (c) 2001 Denis Oliver Kropp <dok@convergence.de>
+ *
+ * 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.
+ */
+
+
+#ifndef __SAVAGEFB_H__
+#define __SAVAGEFB_H__
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+#include "../edid.h"
+
+#ifdef SAVAGEFB_DEBUG
+# define DBG(x) printk (KERN_DEBUG "savagefb: %s\n", (x));
+#else
+# define DBG(x)
+# define SavagePrintRegs(...)
+#endif
+
+
+#define PCI_CHIP_SAVAGE4 0x8a22
+#define PCI_CHIP_SAVAGE3D 0x8a20
+#define PCI_CHIP_SAVAGE3D_MV 0x8a21
+#define PCI_CHIP_SAVAGE2000 0x9102
+#define PCI_CHIP_SAVAGE_MX_MV 0x8c10
+#define PCI_CHIP_SAVAGE_MX 0x8c11
+#define PCI_CHIP_SAVAGE_IX_MV 0x8c12
+#define PCI_CHIP_SAVAGE_IX 0x8c13
+#define PCI_CHIP_PROSAVAGE_PM 0x8a25
+#define PCI_CHIP_PROSAVAGE_KM 0x8a26
+ /* Twister is a code name; hope I get the real name soon. */
+#define PCI_CHIP_S3TWISTER_P 0x8d01
+#define PCI_CHIP_S3TWISTER_K 0x8d02
+#define PCI_CHIP_PROSAVAGE_DDR 0x8d03
+#define PCI_CHIP_PROSAVAGE_DDRK 0x8d04
+#define PCI_CHIP_SUPSAV_MX128 0x8c22
+#define PCI_CHIP_SUPSAV_MX64 0x8c24
+#define PCI_CHIP_SUPSAV_MX64C 0x8c26
+#define PCI_CHIP_SUPSAV_IX128SDR 0x8c2a
+#define PCI_CHIP_SUPSAV_IX128DDR 0x8c2b
+#define PCI_CHIP_SUPSAV_IX64SDR 0x8c2c
+#define PCI_CHIP_SUPSAV_IX64DDR 0x8c2d
+#define PCI_CHIP_SUPSAV_IXCSDR 0x8c2e
+#define PCI_CHIP_SUPSAV_IXCDDR 0x8c2f
+
+
+
+#define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
+
+#define S3_SAVAGE4_SERIES(chip) ((chip==S3_SAVAGE4) || (chip==S3_PROSAVAGE))
+
+#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
+
+#define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+
+
+/* Chip tags. These are used to group the adapters into
+ * related families.
+ */
+
+typedef enum {
+ S3_UNKNOWN = 0,
+ S3_SAVAGE3D,
+ S3_SAVAGE_MX,
+ S3_SAVAGE4,
+ S3_PROSAVAGE,
+ S3_SUPERSAVAGE,
+ S3_SAVAGE2000,
+ S3_LAST
+} savage_chipset;
+
+#define BIOS_BSIZE 1024
+#define BIOS_BASE 0xc0000
+
+#define SAVAGE_NEWMMIO_REGBASE_S3 0x1000000 /* 16MB */
+#define SAVAGE_NEWMMIO_REGBASE_S4 0x0000000
+#define SAVAGE_NEWMMIO_REGSIZE 0x0080000 /* 512kb */
+#define SAVAGE_NEWMMIO_VGABASE 0x8000
+
+#define BASE_FREQ 14318
+#define HALF_BASE_FREQ 7159
+
+#define FIFO_CONTROL_REG 0x8200
+#define MIU_CONTROL_REG 0x8204
+#define STREAMS_TIMEOUT_REG 0x8208
+#define MISC_TIMEOUT_REG 0x820c
+
+#define MONO_PAT_0 0xa4e8
+#define MONO_PAT_1 0xa4ec
+
+#define MAXFIFO 0x7f00
+
+#define BCI_CMD_NOP 0x40000000
+#define BCI_CMD_SETREG 0x96000000
+#define BCI_CMD_RECT 0x48000000
+#define BCI_CMD_RECT_XP 0x01000000
+#define BCI_CMD_RECT_YP 0x02000000
+#define BCI_CMD_SEND_COLOR 0x00008000
+#define BCI_CMD_DEST_GBD 0x00000000
+#define BCI_CMD_SRC_GBD 0x00000020
+#define BCI_CMD_SRC_SOLID 0x00000000
+#define BCI_CMD_SRC_MONO 0x00000060
+#define BCI_CMD_CLIP_NEW 0x00006000
+#define BCI_CMD_CLIP_LR 0x00004000
+
+#define BCI_CLIP_LR(l, r) ((((r) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_TL(t, l) ((((t) << 16) | (l)) & 0x0FFF0FFF)
+#define BCI_CLIP_BR(b, r) ((((b) << 16) | (r)) & 0x0FFF0FFF)
+#define BCI_W_H(w, h) (((h) << 16) | ((w) & 0xFFF))
+#define BCI_X_Y(x, y) (((y) << 16) | ((x) & 0xFFF))
+
+#define BCI_GBD1 0xE0
+#define BCI_GBD2 0xE1
+
+#define BCI_BUFFER_OFFSET 0x10000
+#define BCI_SIZE 0x4000
+
+#define BCI_SEND(dw) writel(dw, par->bci_base + par->bci_ptr++)
+
+#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF)
+#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16))
+#define BCI_CMD_SEND_COLOR 0x00008000
+
+struct xtimings {
+ unsigned int Clock;
+ unsigned int HDisplay;
+ unsigned int HSyncStart;
+ unsigned int HSyncEnd;
+ unsigned int HTotal;
+ unsigned int HAdjusted;
+ unsigned int VDisplay;
+ unsigned int VSyncStart;
+ unsigned int VSyncEnd;
+ unsigned int VTotal;
+ unsigned int sync;
+ int dblscan;
+ int interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+#define NR_PALETTE 256
+
+
+struct savagefb_par;
+
+struct savagefb_i2c_chan {
+ struct savagefb_par *par;
+ struct i2c_adapter adapter;
+ struct i2c_algo_bit_data algo;
+ volatile u8 __iomem *ioaddr;
+ u32 reg;
+};
+
+struct savagefb_par {
+ struct pci_dev *pcidev;
+ savage_chipset chip;
+ struct savagefb_i2c_chan chan;
+ unsigned char *edid;
+ u32 pseudo_palette[16];
+ int dacSpeedBpp;
+ int maxClock;
+ int minClock;
+ int numClocks;
+ int clock[4];
+ struct {
+ u8 __iomem *vbase;
+ u32 pbase;
+ u32 len;
+#ifdef CONFIG_MTRR
+ int mtrr;
+#endif
+ } video;
+
+ struct {
+ volatile u8 __iomem *vbase;
+ u32 pbase;
+ u32 len;
+ } mmio;
+
+ volatile u32 __iomem *bci_base;
+ unsigned int bci_ptr;
+
+ u32 cob_offset;
+ u32 cob_size;
+ int cob_index;
+
+ void (*SavageWaitIdle) (struct savagefb_par *par);
+ void (*SavageWaitFifo) (struct savagefb_par *par, int space);
+
+ int MCLK, REFCLK, LCDclk;
+ int HorizScaleFactor;
+
+ /* Panels size */
+ int SavagePanelWidth;
+ int SavagePanelHeight;
+
+ struct {
+ u16 red, green, blue, transp;
+ } palette[NR_PALETTE];
+
+ int depth;
+ int vwidth;
+
+ unsigned char MiscOutReg; /* Misc */
+ unsigned char CRTC[25]; /* Crtc Controller */
+ unsigned char Sequencer[5]; /* Video Sequencer */
+ unsigned char Graphics[9]; /* Video Graphics */
+ unsigned char Attribute[21]; /* Video Atribute */
+
+ unsigned int mode, refresh;
+ unsigned char SR08, SR0E, SR0F;
+ unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30;
+ unsigned char SR54[8];
+ unsigned char Clock;
+ unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C;
+ unsigned char CR40, CR41, CR42, CR43, CR45;
+ unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E;
+ unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F;
+ unsigned char CR86, CR88;
+ unsigned char CR90, CR91, CRB0;
+ unsigned int STREAMS[22]; /* yuck, streams regs */
+ unsigned int MMPR0, MMPR1, MMPR2, MMPR3;
+};
+
+#define BCI_BD_BW_DISABLE 0x10000000
+#define BCI_BD_SET_BPP(bd, bpp) ((bd) |= (((bpp) & 0xFF) << 16))
+#define BCI_BD_SET_STRIDE(bd, st) ((bd) |= ((st) & 0xFFFF))
+
+
+/* IO functions */
+
+#define vga_in8(addr) (inb (addr))
+#define vga_in16(addr) (inw (addr))
+#define vga_in32(addr) (inl (addr))
+
+#define vga_out8(addr,val) (outb ((val), (addr)))
+#define vga_out16(addr,val) (outw ((val), (addr)))
+#define vga_out32(addr,val) (outl ((val), (addr)))
+
+#define savage_in16(addr) readw(par->mmio.vbase + (addr))
+#define savage_in32(addr) readl(par->mmio.vbase + (addr))
+
+#define savage_out16(addr,val) writew((val), par->mmio.vbase + (addr))
+#define savage_out32(addr,val) writel((val), par->mmio.vbase + (addr))
+
+static inline u8 VGArCR (u8 index)
+{
+ outb (index, 0x3d4);
+ return inb (0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+ outb (index, 0x3ce);
+ return inb (0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+ outb (index, 0x3c4);
+ return inb (0x3c5);
+}
+
+#define VGAwCR(index, val) \
+do { \
+ vga_out8 (0x3d4, index); \
+ vga_out8 (0x3d5, val); \
+} while (0)
+
+#define VGAwGR(index, val) \
+do { \
+ vga_out8 (0x3ce, index); \
+ vga_out8 (0x3cf, val); \
+} while (0)
+
+#define VGAwSEQ(index, val) \
+do { \
+ vga_out8 (0x3c4, index); \
+ vga_out8 (0x3c5, val); \
+} while (0)
+
+#define VGAenablePalette() \
+do { \
+ u8 tmp; \
+ \
+ tmp = vga_in8 (0x3da); \
+ vga_out8 (0x3c0, 0x00); \
+ paletteEnabled = 1; \
+} while (0)
+
+#define VGAdisablePalette() \
+do { \
+ u8 tmp; \
+ \
+ tmp = vga_in8 (0x3da); \
+ vga_out8 (0x3c0, 0x20); \
+ paletteEnabled = 0; \
+} while (0)
+
+#define VGAwATTR(index, value) \
+do { \
+ u8 tmp; \
+ \
+ if (paletteEnabled) \
+ index &= ~0x20; \
+ else \
+ index |= 0x20; \
+ \
+ tmp = vga_in8 (0x3da); \
+ vga_out8 (0x3c0, index); \
+ vga_out8 (0x3c0, value); \
+} while (0)
+
+#define VGAwMISC(value) \
+do { \
+ vga_out8 (0x3c2, value); \
+} while (0)
+
+#ifndef CONFIG_FB_SAVAGE_ACCEL
+#define savagefb_set_clip(x)
+#endif
+
+#define VerticalRetraceWait() \
+{ \
+ vga_out8 (0x3d4, 0x17); \
+ if (vga_in8 (0x3d5) & 0x80) { \
+ while ((vga_in8(0x3da) & 0x08) == 0x08) ; \
+ while ((vga_in8(0x3da) & 0x08) == 0x00) ; \
+ } \
+}
+
+extern int savagefb_probe_i2c_connector(struct savagefb_par *par,
+ u8 **out_edid);
+extern void savagefb_create_i2c_busses(struct fb_info *info);
+extern void savagefb_delete_i2c_busses(struct fb_info *info);
+extern int savagefb_sync(struct fb_info *info);
+extern void savagefb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *region);
+extern void savagefb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect);
+extern void savagefb_imageblit(struct fb_info *info,
+ const struct fb_image *image);
+
+
+#endif /* __SAVAGEFB_H__ */
diff --git a/drivers/video/savage/savagefb_accel.c b/drivers/video/savage/savagefb_accel.c
new file mode 100644
index 00000000000..bac8ea3a010
--- /dev/null
+++ b/drivers/video/savage/savagefb_accel.c
@@ -0,0 +1,136 @@
+/*-*- linux-c -*-
+ * linux/drivers/video/savage/savage_accel.c -- Hardware Acceleration
+ *
+ * Copyright (C) 2004 Antonino Daplas<adaplas@pol.net>
+ * All Rights Reserved
+ *
+ * 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/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include "savagefb.h"
+
+static u32 savagefb_rop[] = {
+ 0xCC, /* ROP_COPY */
+ 0x5A /* ROP_XOR */
+};
+
+int savagefb_sync(struct fb_info *info)
+{
+ struct savagefb_par *par = (struct savagefb_par *)info->par;
+
+ par->SavageWaitIdle(par);
+ return 0;
+}
+
+void savagefb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+{
+ struct savagefb_par *par = (struct savagefb_par *)info->par;
+ int sx = region->sx, dx = region->dx;
+ int sy = region->sy, dy = region->dy;
+ int cmd;
+
+ if (!region->width || !region->height)
+ return;
+ par->bci_ptr = 0;
+ cmd = BCI_CMD_RECT | BCI_CMD_DEST_GBD | BCI_CMD_SRC_GBD;
+ BCI_CMD_SET_ROP(cmd, savagefb_rop[0]);
+
+ if (dx <= sx) {
+ cmd |= BCI_CMD_RECT_XP;
+ } else {
+ sx += region->width - 1;
+ dx += region->width - 1;
+ }
+
+ if (dy <= sy) {
+ cmd |= BCI_CMD_RECT_YP;
+ } else {
+ sy += region->height - 1;
+ dy += region->height - 1;
+ }
+
+ par->SavageWaitFifo(par,4);
+ BCI_SEND(cmd);
+ BCI_SEND(BCI_X_Y(sx, sy));
+ BCI_SEND(BCI_X_Y(dx, dy));
+ BCI_SEND(BCI_W_H(region->width, region->height));
+}
+
+void savagefb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ struct savagefb_par *par = (struct savagefb_par *)info->par;
+ int cmd, color;
+
+ if (!rect->width || !rect->height)
+ return;
+
+ if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+ color = rect->color;
+ else
+ color = ((u32 *)info->pseudo_palette)[rect->color];
+
+ cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+ BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID |
+ BCI_CMD_SEND_COLOR;
+
+ par->bci_ptr = 0;
+ BCI_CMD_SET_ROP(cmd, savagefb_rop[rect->rop]);
+
+ par->SavageWaitFifo(par,4);
+ BCI_SEND(cmd);
+ BCI_SEND(color);
+ BCI_SEND( BCI_X_Y(rect->dx, rect->dy) );
+ BCI_SEND( BCI_W_H(rect->width, rect->height) );
+}
+
+void savagefb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct savagefb_par *par = (struct savagefb_par *)info->par;
+ int fg, bg, size, i, width;
+ int cmd;
+ u32 *src = (u32 *) image->data;
+
+ if (!image->width || !image->height)
+ return;
+
+ if (image->depth != 1) {
+ cfb_imageblit(info, image);
+ return;
+ }
+
+ if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+ fg = image->fg_color;
+ bg = image->bg_color;
+ } else {
+ fg = ((u32 *)info->pseudo_palette)[image->fg_color];
+ bg = ((u32 *)info->pseudo_palette)[image->bg_color];
+ }
+
+ cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
+ BCI_CMD_CLIP_LR | BCI_CMD_DEST_GBD | BCI_CMD_SRC_MONO |
+ BCI_CMD_SEND_COLOR;
+
+ par->bci_ptr = 0;
+ BCI_CMD_SET_ROP(cmd, savagefb_rop[0]);
+
+ width = (image->width + 31) & ~31;
+ size = (width * image->height)/8;
+ size >>= 2;
+
+ par->SavageWaitFifo(par, size + 5);
+ BCI_SEND(cmd);
+ BCI_SEND(BCI_CLIP_LR(image->dx, image->dx + image->width - 1));
+ BCI_SEND(fg);
+ BCI_SEND(bg);
+ BCI_SEND(BCI_X_Y(image->dx, image->dy));
+ BCI_SEND(BCI_W_H(width, image->height));
+ for (i = 0; i < size; i++)
+ BCI_SEND(src[i]);
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
new file mode 100644
index 00000000000..e1c9c946be2
--- /dev/null
+++ b/drivers/video/savage/savagefb_driver.c
@@ -0,0 +1,2279 @@
+/*
+ * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver
+ *
+ * Copyright (c) 2001-2002 Denis Oliver Kropp <dok@directfb.org>
+ * Sven Neumann <neo@directfb.org>
+ *
+ *
+ * Card specific code is based on XFree86's savage driver.
+ * Framebuffer framework code is based on code of cyber2000fb and tdfxfb.
+ *
+ * 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.
+ *
+ * 0.4.0 (neo)
+ * - hardware accelerated clear and move
+ *
+ * 0.3.2 (dok)
+ * - wait for vertical retrace before writing to cr67
+ * at the beginning of savagefb_set_par
+ * - use synchronization registers cr23 and cr26
+ *
+ * 0.3.1 (dok)
+ * - reset 3D engine
+ * - don't return alpha bits for 32bit format
+ *
+ * 0.3.0 (dok)
+ * - added WaitIdle functions for all Savage types
+ * - do WaitIdle before mode switching
+ * - code cleanup
+ *
+ * 0.2.0 (dok)
+ * - first working version
+ *
+ *
+ * TODO
+ * - clock validations in decode_var
+ *
+ * BUGS
+ * - white margin on bootup
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "savagefb.h"
+
+
+#define SAVAGEFB_VERSION "0.4.0_2.6"
+
+/* --------------------------------------------------------------------- */
+
+
+static char *mode_option __initdata = NULL;
+static int paletteEnabled = 0;
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@directfb.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static void vgaHWSeqReset (struct savagefb_par *par, int start)
+{
+ if (start)
+ VGAwSEQ (0x00, 0x01); /* Synchronous Reset */
+ else
+ VGAwSEQ (0x00, 0x03); /* End Reset */
+}
+
+static void vgaHWProtect (struct savagefb_par *par, int on)
+{
+ unsigned char tmp;
+
+ if (on) {
+ /*
+ * Turn off screen and disable sequencer.
+ */
+ tmp = VGArSEQ (0x01);
+
+ vgaHWSeqReset (par, 1); /* start synchronous reset */
+ VGAwSEQ (0x01, tmp | 0x20); /* disable the display */
+
+ VGAenablePalette();
+ } else {
+ /*
+ * Reenable sequencer, then turn on screen.
+ */
+
+ tmp = VGArSEQ (0x01);
+
+ VGAwSEQ (0x01, tmp & ~0x20); /* reenable display */
+ vgaHWSeqReset (par, 0); /* clear synchronous reset */
+
+ VGAdisablePalette();
+ }
+}
+
+static void vgaHWRestore (struct savagefb_par *par)
+{
+ int i;
+
+ VGAwMISC (par->MiscOutReg);
+
+ for (i = 1; i < 5; i++)
+ VGAwSEQ (i, par->Sequencer[i]);
+
+ /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
+ CRTC[17] */
+ VGAwCR (17, par->CRTC[17] & ~0x80);
+
+ for (i = 0; i < 25; i++)
+ VGAwCR (i, par->CRTC[i]);
+
+ for (i = 0; i < 9; i++)
+ VGAwGR (i, par->Graphics[i]);
+
+ VGAenablePalette();
+
+ for (i = 0; i < 21; i++)
+ VGAwATTR (i, par->Attribute[i]);
+
+ VGAdisablePalette();
+}
+
+static void vgaHWInit (struct fb_var_screeninfo *var,
+ struct savagefb_par *par,
+ struct xtimings *timings)
+{
+ par->MiscOutReg = 0x23;
+
+ if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+ par->MiscOutReg |= 0x40;
+
+ if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+ par->MiscOutReg |= 0x80;
+
+ /*
+ * Time Sequencer
+ */
+ par->Sequencer[0x00] = 0x00;
+ par->Sequencer[0x01] = 0x01;
+ par->Sequencer[0x02] = 0x0F;
+ par->Sequencer[0x03] = 0x00; /* Font select */
+ par->Sequencer[0x04] = 0x0E; /* Misc */
+
+ /*
+ * CRTC Controller
+ */
+ par->CRTC[0x00] = (timings->HTotal >> 3) - 5;
+ par->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
+ par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
+ par->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80;
+ par->CRTC[0x04] = (timings->HSyncStart >> 3);
+ par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
+ (((timings->HSyncEnd >> 3)) & 0x1f);
+ par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
+ par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
+ (((timings->VDisplay - 1) & 0x100) >> 7) |
+ ((timings->VSyncStart & 0x100) >> 6) |
+ (((timings->VSyncStart - 1) & 0x100) >> 5) |
+ 0x10 |
+ (((timings->VTotal - 2) & 0x200) >> 4) |
+ (((timings->VDisplay - 1) & 0x200) >> 3) |
+ ((timings->VSyncStart & 0x200) >> 2);
+ par->CRTC[0x08] = 0x00;
+ par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
+
+ if (timings->dblscan)
+ par->CRTC[0x09] |= 0x80;
+
+ par->CRTC[0x0a] = 0x00;
+ par->CRTC[0x0b] = 0x00;
+ par->CRTC[0x0c] = 0x00;
+ par->CRTC[0x0d] = 0x00;
+ par->CRTC[0x0e] = 0x00;
+ par->CRTC[0x0f] = 0x00;
+ par->CRTC[0x10] = timings->VSyncStart & 0xff;
+ par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
+ par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
+ par->CRTC[0x13] = var->xres_virtual >> 4;
+ par->CRTC[0x14] = 0x00;
+ par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
+ par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
+ par->CRTC[0x17] = 0xc3;
+ par->CRTC[0x18] = 0xff;
+
+ /*
+ * are these unnecessary?
+ * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
+ * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
+ */
+
+ /*
+ * Graphics Display Controller
+ */
+ par->Graphics[0x00] = 0x00;
+ par->Graphics[0x01] = 0x00;
+ par->Graphics[0x02] = 0x00;
+ par->Graphics[0x03] = 0x00;
+ par->Graphics[0x04] = 0x00;
+ par->Graphics[0x05] = 0x40;
+ par->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */
+ par->Graphics[0x07] = 0x0F;
+ par->Graphics[0x08] = 0xFF;
+
+
+ par->Attribute[0x00] = 0x00; /* standard colormap translation */
+ par->Attribute[0x01] = 0x01;
+ par->Attribute[0x02] = 0x02;
+ par->Attribute[0x03] = 0x03;
+ par->Attribute[0x04] = 0x04;
+ par->Attribute[0x05] = 0x05;
+ par->Attribute[0x06] = 0x06;
+ par->Attribute[0x07] = 0x07;
+ par->Attribute[0x08] = 0x08;
+ par->Attribute[0x09] = 0x09;
+ par->Attribute[0x0a] = 0x0A;
+ par->Attribute[0x0b] = 0x0B;
+ par->Attribute[0x0c] = 0x0C;
+ par->Attribute[0x0d] = 0x0D;
+ par->Attribute[0x0e] = 0x0E;
+ par->Attribute[0x0f] = 0x0F;
+ par->Attribute[0x10] = 0x41;
+ par->Attribute[0x11] = 0xFF;
+ par->Attribute[0x12] = 0x0F;
+ par->Attribute[0x13] = 0x00;
+ par->Attribute[0x14] = 0x00;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for SavageFB
+ */
+
+/* Wait for fifo space */
+static void
+savage3D_waitfifo(struct savagefb_par *par, int space)
+{
+ int slots = MAXFIFO - space;
+
+ while ((savage_in32(0x48C00) & 0x0000ffff) > slots);
+}
+
+static void
+savage4_waitfifo(struct savagefb_par *par, int space)
+{
+ int slots = MAXFIFO - space;
+
+ while ((savage_in32(0x48C60) & 0x001fffff) > slots);
+}
+
+static void
+savage2000_waitfifo(struct savagefb_par *par, int space)
+{
+ int slots = MAXFIFO - space;
+
+ while ((savage_in32(0x48C60) & 0x0000ffff) > slots);
+}
+
+/* Wait for idle accelerator */
+static void
+savage3D_waitidle(struct savagefb_par *par)
+{
+ while ((savage_in32(0x48C00) & 0x0008ffff) != 0x80000);
+}
+
+static void
+savage4_waitidle(struct savagefb_par *par)
+{
+ while ((savage_in32(0x48C60) & 0x00a00000) != 0x00a00000);
+}
+
+static void
+savage2000_waitidle(struct savagefb_par *par)
+{
+ while ((savage_in32(0x48C60) & 0x009fffff));
+}
+
+
+static void
+SavageSetup2DEngine (struct savagefb_par *par)
+{
+ unsigned long GlobalBitmapDescriptor;
+
+ GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
+ BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth);
+ BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth);
+
+ switch(par->chip) {
+ case S3_SAVAGE3D:
+ case S3_SAVAGE_MX:
+ /* Disable BCI */
+ savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0);
+ /* Setup BCI command overflow buffer */
+ savage_out32(0x48C14, (par->cob_offset >> 11) | (par->cob_index << 29));
+ /* Program shadow status update. */
+ savage_out32(0x48C10, 0x78207220);
+ savage_out32(0x48C0C, 0);
+ /* Enable BCI a