OSDN Git Service

Merge branch 'viafb-next' of git://git.lwn.net/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 20 May 2010 20:34:17 +0000 (13:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 20 May 2010 20:34:17 +0000 (13:34 -0700)
* 'viafb-next' of git://git.lwn.net/linux-2.6: (35 commits)
  viafb: move some include files to include/linux
  viafb: Eliminate some global.h references
  viafb: get rid of i2c debug cruft
  viafb: fold via_io.h into via-core.h
  viafb: Fix initialization error paths
  viafb: Do not remove gpiochip under spinlock
  viafb: make procfs entries optional
  viafb: fix proc entry removal
  viafb: improve misc register handling
  viafb: replace inb/outb
  viafb: move some modesetting functions to a seperate file
  viafb: unify modesetting functions
  viafb: Reserve framebuffer memory for the upcoming camera driver
  viafb: Add a simple VX855 DMA engine driver
  viafb: Add a simple interrupt management infrastructure
  via: Rationalize vt1636 detection
  viafb: Introduce viafb_find_i2c_adapter()
  via: Do not attempt I/O on inactive I2C adapters
  viafb: Turn GPIO and i2c into proper platform devices
  viafb: Convert GPIO and i2c to the new indexed port ops
  ...

27 files changed:
drivers/video/Kconfig
drivers/video/via/Makefile
drivers/video/via/accel.c
drivers/video/via/accel.h
drivers/video/via/chip.h
drivers/video/via/dvi.c
drivers/video/via/global.h
drivers/video/via/hw.c
drivers/video/via/hw.h
drivers/video/via/ioctl.h
drivers/video/via/lcd.c
drivers/video/via/lcd.h
drivers/video/via/share.h
drivers/video/via/via-core.c [new file with mode: 0644]
drivers/video/via/via-gpio.c [new file with mode: 0644]
drivers/video/via/via_i2c.c
drivers/video/via/via_modesetting.c [new file with mode: 0644]
drivers/video/via/via_modesetting.h [new file with mode: 0644]
drivers/video/via/via_utility.c
drivers/video/via/viafbdev.c
drivers/video/via/viafbdev.h
drivers/video/via/viamode.c
drivers/video/via/vt1636.c
drivers/video/via/vt1636.h
include/linux/via-core.h [new file with mode: 0644]
include/linux/via-gpio.h [new file with mode: 0644]
include/linux/via_i2c.h [moved from drivers/video/via/via_i2c.h with 65% similarity]

index 6e16244..fd55c27 100644 (file)
@@ -1511,6 +1511,7 @@ config FB_VIA
        select FB_CFB_IMAGEBLIT
        select I2C_ALGOBIT
        select I2C
+       select GPIOLIB
        help
          This is the frame buffer device driver for Graphics chips of VIA
          UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
@@ -1520,6 +1521,21 @@ config FB_VIA
 
          To compile this driver as a module, choose M here: the
          module will be called viafb.
+
+if FB_VIA
+
+config FB_VIA_DIRECT_PROCFS
+       bool "direct hardware access via procfs (DEPRECATED)(DANGEROUS)"
+       depends on FB_VIA
+       default n
+       help
+         Allow direct hardware access to some output registers via procfs.
+         This is dangerous but may provide the only chance to get the
+         correct output device configuration.
+         Its use is strongly discouraged.
+
+endif
+
 config FB_NEOMAGIC
        tristate "NeoMagic display support"
        depends on FB && PCI
index eeed238..d496adb 100644 (file)
@@ -4,4 +4,6 @@
 
 obj-$(CONFIG_FB_VIA) += viafb.o
 
-viafb-y        :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o
+viafb-y        :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \
+       via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o \
+       via-core.o via-gpio.o via_modesetting.o
index d5077df..e44893e 100644 (file)
  * Foundation, Inc.,
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
+#include <linux/via-core.h>
 #include "global.h"
 
+/*
+ * Figure out an appropriate bytes-per-pixel setting.
+ */
+static int viafb_set_bpp(void __iomem *engine, u8 bpp)
+{
+       u32 gemode;
+
+       /* Preserve the reserved bits */
+       /* Lowest 2 bits to zero gives us no rotation */
+       gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
+       switch (bpp) {
+       case 8:
+               gemode |= VIA_GEM_8bpp;
+               break;
+       case 16:
+               gemode |= VIA_GEM_16bpp;
+               break;
+       case 32:
+               gemode |= VIA_GEM_32bpp;
+               break;
+       default:
+               printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
+               return -EINVAL;
+       }
+       writel(gemode, engine + VIA_REG_GEMODE);
+       return 0;
+}
+
+
 static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
        u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
        u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
        u32 fg_color, u32 bg_color, u8 fill_rop)
 {
        u32 ge_cmd = 0, tmp, i;
+       int ret;
 
        if (!op || op > 3) {
                printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
@@ -59,22 +90,9 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
                }
        }
 
-       switch (dst_bpp) {
-       case 8:
-               tmp = 0x00000000;
-               break;
-       case 16:
-               tmp = 0x00000100;
-               break;
-       case 32:
-               tmp = 0x00000300;
-               break;
-       default:
-               printk(KERN_WARNING "hw_bitblt_1: Unsupported bpp %d\n",
-                       dst_bpp);
-               return -EINVAL;
-       }
-       writel(tmp, engine + 0x04);
+       ret = viafb_set_bpp(engine, dst_bpp);
+       if (ret)
+               return ret;
 
        if (op != VIA_BITBLT_FILL) {
                if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
@@ -171,6 +189,7 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
        u32 fg_color, u32 bg_color, u8 fill_rop)
 {
        u32 ge_cmd = 0, tmp, i;
+       int ret;
 
        if (!op || op > 3) {
                printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
@@ -204,22 +223,9 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
                }
        }
 
-       switch (dst_bpp) {
-       case 8:
-               tmp = 0x00000000;
-               break;
-       case 16:
-               tmp = 0x00000100;
-               break;
-       case 32:
-               tmp = 0x00000300;
-               break;
-       default:
-               printk(KERN_WARNING "hw_bitblt_2: Unsupported bpp %d\n",
-                       dst_bpp);
-               return -EINVAL;
-       }
-       writel(tmp, engine + 0x04);
+       ret = viafb_set_bpp(engine, dst_bpp);
+       if (ret)
+               return ret;
 
        if (op == VIA_BITBLT_FILL)
                tmp = 0;
@@ -312,17 +318,29 @@ int viafb_init_engine(struct fb_info *info)
 {
        struct viafb_par *viapar = info->par;
        void __iomem *engine;
+       int highest_reg, i;
        u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
                vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
 
-       engine = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
-       viapar->shared->engine_mmio = engine;
+       engine = viapar->shared->vdev->engine_mmio;
        if (!engine) {
                printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
                        "hardware acceleration disabled\n");
                return -ENOMEM;
        }
 
+       /* Initialize registers to reset the 2D engine */
+       switch (viapar->shared->chip_info.twod_engine) {
+       case VIA_2D_ENG_M1:
+               highest_reg = 0x5c;
+               break;
+       default:
+               highest_reg = 0x40;
+               break;
+       }
+       for (i = 0; i <= highest_reg; i += 4)
+               writel(0x0, engine + i);
+
        switch (chip_name) {
        case UNICHROME_CLE266:
        case UNICHROME_K400:
@@ -352,13 +370,28 @@ int viafb_init_engine(struct fb_info *info)
        viapar->shared->vq_vram_addr = viapar->fbmem_free;
        viapar->fbmem_used += VQ_SIZE;
 
-       /* Init 2D engine reg to reset 2D engine */
-       writel(0x0, engine + VIA_REG_KEYCONTROL);
+#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
+       /*
+        * Set aside a chunk of framebuffer memory for the camera
+        * driver.  Someday this driver probably needs a proper allocator
+        * for fbmem; for now, we just have to do this before the
+        * framebuffer initializes itself.
+        *
+        * As for the size: the engine can handle three frames,
+        * 16 bits deep, up to VGA resolution.
+        */
+       viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
+       viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
+       viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
+       viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
+#endif
 
        /* Init AGP and VQ regs */
        switch (chip_name) {
        case UNICHROME_K8M890:
        case UNICHROME_P4M900:
+       case UNICHROME_VX800:
+       case UNICHROME_VX855:
                writel(0x00100000, engine + VIA_REG_CR_TRANSET);
                writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
                writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
@@ -393,6 +426,8 @@ int viafb_init_engine(struct fb_info *info)
        switch (chip_name) {
        case UNICHROME_K8M890:
        case UNICHROME_P4M900:
+       case UNICHROME_VX800:
+       case UNICHROME_VX855:
                vq_start_low |= 0x20000000;
                vq_end_low |= 0x20000000;
                vq_high |= 0x20000000;
@@ -446,7 +481,7 @@ void viafb_show_hw_cursor(struct fb_info *info, int Status)
        struct viafb_par *viapar = info->par;
        u32 temp, iga_path = viapar->iga_path;
 
-       temp = readl(viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE);
+       temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
        switch (Status) {
        case HW_Cursor_ON:
                temp |= 0x1;
@@ -463,23 +498,33 @@ void viafb_show_hw_cursor(struct fb_info *info, int Status)
        default:
                temp &= 0x7FFFFFFF;
        }
-       writel(temp, viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE);
+       writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
 }
 
 void viafb_wait_engine_idle(struct fb_info *info)
 {
        struct viafb_par *viapar = info->par;
        int loop = 0;
-
-       while (!(readl(viapar->shared->engine_mmio + VIA_REG_STATUS) &
-                       VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
-               loop++;
-               cpu_relax();
+       u32 mask;
+       void __iomem *engine = viapar->shared->vdev->engine_mmio;
+
+       switch (viapar->shared->chip_info.twod_engine) {
+       case VIA_2D_ENG_H5:
+       case VIA_2D_ENG_M1:
+               mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
+                             VIA_3D_ENG_BUSY_M1;
+               break;
+       default:
+               while (!(readl(engine + VIA_REG_STATUS) &
+                               VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
+                       loop++;
+                       cpu_relax();
+               }
+               mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
+               break;
        }
 
-       while ((readl(viapar->shared->engine_mmio + VIA_REG_STATUS) &
-                   (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
-                   (loop < MAXLOOP)) {
+       while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
                loop++;
                cpu_relax();
        }
index 615c84a..2c122d2 100644 (file)
 /* from 0x100 to 0x1ff */
 #define VIA_REG_COLORPAT        0x100
 
+/* defines for VIA 2D registers for vt3353/3409 (M1 engine)*/
+#define VIA_REG_GECMD_M1        0x000
+#define VIA_REG_GEMODE_M1       0x004
+#define VIA_REG_GESTATUS_M1     0x004       /* as same as VIA_REG_GEMODE */
+#define VIA_REG_PITCH_M1        0x008       /* pitch of src and dst */
+#define VIA_REG_DIMENSION_M1    0x00C       /* width and height */
+#define VIA_REG_DSTPOS_M1       0x010
+#define VIA_REG_LINE_XY_M1      0x010
+#define VIA_REG_DSTBASE_M1      0x014
+#define VIA_REG_SRCPOS_M1       0x018
+#define VIA_REG_LINE_K1K2_M1    0x018
+#define VIA_REG_SRCBASE_M1      0x01C
+#define VIA_REG_PATADDR_M1      0x020
+#define VIA_REG_MONOPAT0_M1     0x024
+#define VIA_REG_MONOPAT1_M1     0x028
+#define VIA_REG_OFFSET_M1       0x02C
+#define VIA_REG_LINE_ERROR_M1   0x02C
+#define VIA_REG_CLIPTL_M1       0x040       /* top and left of clipping */
+#define VIA_REG_CLIPBR_M1       0x044       /* bottom and right of clipping */
+#define VIA_REG_KEYCONTROL_M1   0x048       /* color key control */
+#define VIA_REG_FGCOLOR_M1      0x04C
+#define VIA_REG_DSTCOLORKEY_M1  0x04C       /* as same as VIA_REG_FG */
+#define VIA_REG_BGCOLOR_M1      0x050
+#define VIA_REG_SRCCOLORKEY_M1  0x050       /* as same as VIA_REG_BG */
+#define VIA_REG_MONOPATFGC_M1   0x058       /* Add BG color of Pattern. */
+#define VIA_REG_MONOPATBGC_M1   0x05C       /* Add FG color of Pattern. */
+#define VIA_REG_COLORPAT_M1     0x100       /* from 0x100 to 0x1ff */
+
 /* VIA_REG_PITCH(0x38): Pitch Setting */
 #define VIA_PITCH_ENABLE        0x80000000
 
 /* Virtual Queue is busy */
 #define VIA_VR_QUEUE_BUSY       0x00020000
 
+/* VIA_REG_STATUS(0x400): Engine Status for H5 */
+#define VIA_CMD_RGTR_BUSY_H5   0x00000010  /* Command Regulator is busy */
+#define VIA_2D_ENG_BUSY_H5     0x00000002  /* 2D Engine is busy */
+#define VIA_3D_ENG_BUSY_H5     0x00001FE1  /* 3D Engine is busy */
+#define VIA_VR_QUEUE_BUSY_H5   0x00000004  /* Virtual Queue is busy */
+
+/* VIA_REG_STATUS(0x400): Engine Status for VT3353/3409 */
+#define VIA_CMD_RGTR_BUSY_M1   0x00000010  /* Command Regulator is busy */
+#define VIA_2D_ENG_BUSY_M1     0x00000002  /* 2D Engine is busy */
+#define VIA_3D_ENG_BUSY_M1     0x00001FE1  /* 3D Engine is busy */
+#define VIA_VR_QUEUE_BUSY_M1   0x00000004  /* Virtual Queue is busy */
+
 #define MAXLOOP                 0xFFFFFF
 
 #define VIA_BITBLT_COLOR       1
index 8c06bd3..d9b6e06 100644 (file)
@@ -121,9 +121,17 @@ struct lvds_chip_information {
        int i2c_port;
 };
 
+/* The type of 2D engine */
+enum via_2d_engine {
+       VIA_2D_ENG_H2,
+       VIA_2D_ENG_H5,
+       VIA_2D_ENG_M1,
+};
+
 struct chip_information {
        int gfx_chip_name;
        int gfx_chip_revision;
+       enum via_2d_engine twod_engine;
        struct tmds_chip_information tmds_chip_info;
        struct lvds_chip_information lvds_chip_info;
        struct lvds_chip_information lvds_chip_info2;
index abe59b8..39b040b 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc.,
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
 #include "global.h"
 
 static void tmds_register_write(int index, u8 data);
@@ -96,7 +98,7 @@ int viafb_tmds_trasmitter_identify(void)
        viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS;
        viaparinfo->chip_info->
                tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
-       viaparinfo->chip_info->tmds_chip_info.i2c_port = I2CPORTINDEX;
+       viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_31;
        if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) {
                /*
                 * Currently only support 12bits,dual edge,add 24bits mode later
@@ -110,7 +112,7 @@ int viafb_tmds_trasmitter_identify(void)
                          viaparinfo->chip_info->tmds_chip_info.i2c_port);
                return OK;
        } else {
-               viaparinfo->chip_info->tmds_chip_info.i2c_port = GPIOPORTINDEX;
+               viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_2C;
                if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)
                    != FAIL) {
                        tmds_register_write(0x08, 0x3b);
@@ -160,32 +162,26 @@ int viafb_tmds_trasmitter_identify(void)
 
 static void tmds_register_write(int index, u8 data)
 {
-       viaparinfo->shared->i2c_stuff.i2c_port =
-               viaparinfo->chip_info->tmds_chip_info.i2c_port;
-
-       viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.
-               tmds_chip_slave_addr, index,
-                    data);
+       viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.i2c_port,
+                           viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
+                           index, data);
 }
 
 static int tmds_register_read(int index)
 {
        u8 data;
 
-       viaparinfo->shared->i2c_stuff.i2c_port =
-               viaparinfo->chip_info->tmds_chip_info.i2c_port;
-       viafb_i2c_readbyte((u8) viaparinfo->chip_info->
-           tmds_chip_info.tmds_chip_slave_addr,
-                       (u8) index, &data);
+       viafb_i2c_readbyte(viaparinfo->chip_info->tmds_chip_info.i2c_port,
+                          (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
+                          (u8) index, &data);
        return data;
 }
 
 static int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
 {
-       viaparinfo->shared->i2c_stuff.i2c_port =
-               viaparinfo->chip_info->tmds_chip_info.i2c_port;
-       viafb_i2c_readbytes((u8) viaparinfo->chip_info->tmds_chip_info.
-                        tmds_chip_slave_addr, (u8) index, buff, buff_len);
+       viafb_i2c_readbytes(viaparinfo->chip_info->tmds_chip_info.i2c_port,
+                           (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
+                           (u8) index, buff, buff_len);
        return 0;
 }
 
@@ -541,9 +537,10 @@ void viafb_dvi_enable(void)
                                else
                                        data = 0x37;
                                viafb_i2c_writebyte(viaparinfo->chip_info->
-                                            tmds_chip_info.
-                                            tmds_chip_slave_addr,
-                                            0x08, data);
+                                                      tmds_chip_info.i2c_port,
+                                                   viaparinfo->chip_info->
+                                                      tmds_chip_info.tmds_chip_slave_addr,
+                                                   0x08, data);
                        }
                }
        }
index 8d95d5f..28221a0 100644 (file)
@@ -41,7 +41,6 @@
 #include "share.h"
 #include "dvi.h"
 #include "viamode.h"
-#include "via_i2c.h"
 #include "hw.h"
 
 #include "lcd.h"
index f2583b1..b996803 100644 (file)
@@ -19,6 +19,7 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/via-core.h>
 #include "global.h"
 
 static struct pll_map pll_value[] = {
@@ -62,6 +63,7 @@ static struct pll_map pll_value[] = {
         CX700_52_977M, VX855_52_977M},
        {CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M,
         CX700_56_250M, VX855_56_250M},
+       {CLK_57_275M, 0, 0, 0, VX855_57_275M},
        {CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M,
         CX700_60_466M, VX855_60_466M},
        {CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M,
@@ -525,8 +527,7 @@ static void dvi_patch_skew_dvp_low(void);
 static void set_dvi_output_path(int set_iga, int output_interface);
 static void set_lcd_output_path(int set_iga, int output_interface);
 static void load_fix_bit_crtc_reg(void);
-static void init_gfx_chip_info(struct pci_dev *pdev,
-                               const struct pci_device_id *pdi);
+static void init_gfx_chip_info(int chip_type);
 static void init_tmds_chip_info(void);
 static void init_lvds_chip_info(void);
 static void device_screen_off(void);
@@ -537,18 +538,6 @@ static void device_on(void);
 static void enable_second_display_channel(void);
 static void disable_second_display_channel(void);
 
-void viafb_write_reg(u8 index, u16 io_port, u8 data)
-{
-       outb(index, io_port);
-       outb(data, io_port + 1);
-       /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, data); */
-}
-u8 viafb_read_reg(int io_port, u8 index)
-{
-       outb(index, io_port);
-       return inb(io_port + 1);
-}
-
 void viafb_lock_crt(void)
 {
        viafb_write_reg_mask(CR11, VIACR, BIT7, BIT7);
@@ -560,16 +549,6 @@ void viafb_unlock_crt(void)
        viafb_write_reg_mask(CR47, VIACR, 0, BIT0);
 }
 
-void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask)
-{
-       u8 tmp;
-
-       outb(index, io_port);
-       tmp = inb(io_port + 1);
-       outb((data & mask) | (tmp & (~mask)), io_port + 1);
-       /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, tmp); */
-}
-
 void write_dac_reg(u8 index, u8 r, u8 g, u8 b)
 {
        outb(index, LUT_INDEX_WRITE);
@@ -646,102 +625,6 @@ void viafb_set_iga_path(void)
        }
 }
 
-void viafb_set_primary_address(u32 addr)
-{
-       DEBUG_MSG(KERN_DEBUG "viafb_set_primary_address(0x%08X)\n", addr);
-       viafb_write_reg(CR0D, VIACR, addr & 0xFF);
-       viafb_write_reg(CR0C, VIACR, (addr >> 8) & 0xFF);
-       viafb_write_reg(CR34, VIACR, (addr >> 16) & 0xFF);
-       viafb_write_reg_mask(CR48, VIACR, (addr >> 24) & 0x1F, 0x1F);
-}
-
-void viafb_set_secondary_address(u32 addr)
-{
-       DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_address(0x%08X)\n", addr);
-       /* secondary display supports only quadword aligned memory */
-       viafb_write_reg_mask(CR62, VIACR, (addr >> 2) & 0xFE, 0xFE);
-       viafb_write_reg(CR63, VIACR, (addr >> 10) & 0xFF);
-       viafb_write_reg(CR64, VIACR, (addr >> 18) & 0xFF);
-       viafb_write_reg_mask(CRA3, VIACR, (addr >> 26) & 0x07, 0x07);
-}
-
-void viafb_set_primary_pitch(u32 pitch)
-{
-       DEBUG_MSG(KERN_DEBUG "viafb_set_primary_pitch(0x%08X)\n", pitch);
-       /* spec does not say that first adapter skips 3 bits but old
-        * code did it and seems to be reasonable in analogy to 2nd adapter
-        */
-       pitch = pitch >> 3;
-       viafb_write_reg(0x13, VIACR, pitch & 0xFF);
-       viafb_write_reg_mask(0x35, VIACR, (pitch >> (8 - 5)) & 0xE0, 0xE0);
-}
-
-void viafb_set_secondary_pitch(u32 pitch)
-{
-       DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_pitch(0x%08X)\n", pitch);
-       pitch = pitch >> 3;
-       viafb_write_reg(0x66, VIACR, pitch & 0xFF);
-       viafb_write_reg_mask(0x67, VIACR, (pitch >> 8) & 0x03, 0x03);
-       viafb_write_reg_mask(0x71, VIACR, (pitch >> (10 - 7)) & 0x80, 0x80);
-}
-
-void viafb_set_primary_color_depth(u8 depth)
-{
-       u8 value;
-
-       DEBUG_MSG(KERN_DEBUG "viafb_set_primary_color_depth(%d)\n", depth);
-       switch (depth) {
-       case 8:
-               value = 0x00;
-               break;
-       case 15:
-               value = 0x04;
-               break;
-       case 16:
-               value = 0x14;
-               break;
-       case 24:
-               value = 0x0C;
-               break;
-       case 30:
-               value = 0x08;
-               break;
-       default:
-               printk(KERN_WARNING "viafb_set_primary_color_depth: "
-                       "Unsupported depth: %d\n", depth);
-               return;
-       }
-
-       viafb_write_reg_mask(0x15, VIASR, value, 0x1C);
-}
-
-void viafb_set_secondary_color_depth(u8 depth)
-{
-       u8 value;
-
-       DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_color_depth(%d)\n", depth);
-       switch (depth) {
-       case 8:
-               value = 0x00;
-               break;
-       case 16:
-               value = 0x40;
-               break;
-       case 24:
-               value = 0xC0;
-               break;
-       case 30:
-               value = 0x80;
-               break;
-       default:
-               printk(KERN_WARNING "viafb_set_secondary_color_depth: "
-                       "Unsupported depth: %d\n", depth);
-               return;
-       }
-
-       viafb_write_reg_mask(0x67, VIACR, value, 0xC0);
-}
-
 static void set_color_register(u8 index, u8 red, u8 green, u8 blue)
 {
        outb(0xFF, 0x3C6); /* bit mask of palette */
@@ -1126,16 +1009,12 @@ void viafb_load_reg(int timing_value, int viafb_load_reg_num,
 void viafb_write_regx(struct io_reg RegTable[], int ItemNum)
 {
        int i;
-       unsigned char RegTemp;
 
        /*DEBUG_MSG(KERN_INFO "Table Size : %x!!\n",ItemNum ); */
 
-       for (i = 0; i < ItemNum; i++) {
-               outb(RegTable[i].index, RegTable[i].port);
-               RegTemp = inb(RegTable[i].port + 1);
-               RegTemp = (RegTemp & (~RegTable[i].mask)) | RegTable[i].value;
-               outb(RegTemp, RegTable[i].port + 1);
-       }
+       for (i = 0; i < ItemNum; i++)
+               via_write_reg_mask(RegTable[i].port, RegTable[i].index,
+                       RegTable[i].value, RegTable[i].mask);
 }
 
 void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga)
@@ -1516,8 +1395,6 @@ u32 viafb_get_clk_value(int clk)
 /* Set VCLK*/
 void viafb_set_vclock(u32 CLK, int set_iga)
 {
-       unsigned char RegTemp;
-
        /* H.W. Reset : ON */
        viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
 
@@ -1590,8 +1467,7 @@ void viafb_set_vclock(u32 CLK, int set_iga)
        }
 
        /* Fire! */
-       RegTemp = inb(VIARMisc);
-       outb(RegTemp | (BIT2 + BIT3), VIAWMisc);
+       via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */
 }
 
 void viafb_load_crtc_timing(struct display_timing device_timing,
@@ -1835,6 +1711,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
        int index = 0;
        int h_addr, v_addr;
        u32 pll_D_N;
+       u8 polarity = 0;
 
        for (i = 0; i < video_mode->mode_array; i++) {
                index = i;
@@ -1863,20 +1740,11 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
        v_addr = crt_reg.ver_addr;
 
        /* update polarity for CRT timing */
-       if (crt_table[index].h_sync_polarity == NEGATIVE) {
-               if (crt_table[index].v_sync_polarity == NEGATIVE)
-                       outb((inb(VIARMisc) & (~(BIT6 + BIT7))) |
-                            (BIT6 + BIT7), VIAWMisc);
-               else
-                       outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT6),
-                            VIAWMisc);
-       } else {
-               if (crt_table[index].v_sync_polarity == NEGATIVE)
-                       outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT7),
-                            VIAWMisc);
-               else
-                       outb((inb(VIARMisc) & (~(BIT6 + BIT7))), VIAWMisc);
-       }
+       if (crt_table[index].h_sync_polarity == NEGATIVE)
+               polarity |= BIT6;
+       if (crt_table[index].v_sync_polarity == NEGATIVE)
+               polarity |= BIT7;
+       via_write_misc_reg_mask(polarity, BIT6 | BIT7);
 
        if (set_iga == IGA1) {
                viafb_unlock_crt();
@@ -1910,10 +1778,9 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
 
 }
 
-void viafb_init_chip_info(struct pci_dev *pdev,
-                         const struct pci_device_id *pdi)
+void viafb_init_chip_info(int chip_type)
 {
-       init_gfx_chip_info(pdev, pdi);
+       init_gfx_chip_info(chip_type);
        init_tmds_chip_info();
        init_lvds_chip_info();
 
@@ -1980,12 +1847,11 @@ void viafb_update_device_setting(int hres, int vres,
        }
 }
 
-static void init_gfx_chip_info(struct pci_dev *pdev,
-                              const struct pci_device_id *pdi)
+static void init_gfx_chip_info(int chip_type)
 {
        u8 tmp;
 
-       viaparinfo->chip_info->gfx_chip_name = pdi->driver_data;
+       viaparinfo->chip_info->gfx_chip_name = chip_type;
 
        /* Check revision of CLE266 Chip */
        if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
@@ -2016,6 +1882,21 @@ static void init_gfx_chip_info(struct pci_dev *pdev,
                                CX700_REVISION_700;
                }
        }
+
+       /* Determine which 2D engine we have */
+       switch (viaparinfo->chip_info->gfx_chip_name) {
+       case UNICHROME_VX800:
+       case UNICHROME_VX855:
+               viaparinfo->chip_info->twod_engine = VIA_2D_ENG_M1;
+               break;
+       case UNICHROME_K8M890:
+       case UNICHROME_P4M900:
+               viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H5;
+               break;
+       default:
+               viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H2;
+               break;
+       }
 }
 
 static void init_tmds_chip_info(void)
@@ -2232,13 +2113,11 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
 
        /* Fill VPIT Parameters */
        /* Write Misc Register */
-       outb(VPIT.Misc, VIAWMisc);
+       outb(VPIT.Misc, VIA_MISC_REG_WRITE);
 
        /* Write Sequencer */
-       for (i = 1; i <= StdSR; i++) {
-               outb(i, VIASR);
-               outb(VPIT.SR[i - 1], VIASR + 1);
-       }
+       for (i = 1; i <= StdSR; i++)
+               via_write_reg(VIASR, i, VPIT.SR[i - 1]);
 
        viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2);
        viafb_set_iga_path();
@@ -2247,10 +2126,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
        viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1);
 
        /* Write Graphic Controller */
-       for (i = 0; i < StdGR; i++) {
-               outb(i, VIAGR);
-               outb(VPIT.GR[i], VIAGR + 1);
-       }
+       for (i = 0; i < StdGR; i++)
+               via_write_reg(VIAGR, i, VPIT.GR[i]);
 
        /* Write Attribute Controller */
        for (i = 0; i < StdAR; i++) {
@@ -2277,11 +2154,11 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
                }
        }
 
-       viafb_set_primary_pitch(viafbinfo->fix.line_length);
-       viafb_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
+       via_set_primary_pitch(viafbinfo->fix.line_length);
+       via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
                : viafbinfo->fix.line_length);
-       viafb_set_primary_color_depth(viaparinfo->depth);
-       viafb_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
+       via_set_primary_color_depth(viaparinfo->depth);
+       via_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
                : viaparinfo->depth);
        /* Update Refresh Rate Setting */
 
@@ -2473,108 +2350,6 @@ static void disable_second_display_channel(void)
        viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6);
 }
 
-int viafb_get_fb_size_from_pci(void)
-{
-       unsigned long configid, deviceid, FBSize = 0;
-       int VideoMemSize;
-       int DeviceFound = false;
-
-       for (configid = 0x80000000; configid < 0x80010800; configid += 0x100) {
-               outl(configid, (unsigned long)0xCF8);
-               deviceid = (inl((unsigned long)0xCFC) >> 16) & 0xffff;
-
-               switch (deviceid) {
-               case CLE266:
-               case KM400:
-                       outl(configid + 0xE0, (unsigned long)0xCF8);
-                       FBSize = inl((unsigned long)0xCFC);
-                       DeviceFound = true;     /* Found device id */
-                       break;
-
-               case CN400_FUNCTION3:
-               case CN700_FUNCTION3:
-               case CX700_FUNCTION3:
-               case KM800_FUNCTION3:
-               case KM890_FUNCTION3:
-               case P4M890_FUNCTION3:
-               case P4M900_FUNCTION3:
-               case VX800_FUNCTION3:
-               case VX855_FUNCTION3:
-                       /*case CN750_FUNCTION3: */
-                       outl(configid + 0xA0, (unsigned long)0xCF8);
-                       FBSize = inl((unsigned long)0xCFC);
-                       DeviceFound = true;     /* Found device id */
-                       break;
-
-               default:
-                       break;
-               }
-
-               if (DeviceFound)
-                       break;
-       }
-
-       DEBUG_MSG(KERN_INFO "Device ID = %lx\n", deviceid);
-
-       FBSize = FBSize & 0x00007000;
-       DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
-
-       if (viaparinfo->chip_info->gfx_chip_name < UNICHROME_CX700) {
-               switch (FBSize) {
-               case 0x00004000:
-                       VideoMemSize = (16 << 20);      /*16M */
-                       break;
-
-               case 0x00005000:
-                       VideoMemSize = (32 << 20);      /*32M */
-                       break;
-
-               case 0x00006000:
-                       VideoMemSize = (64 << 20);      /*64M */
-                       break;
-
-               default:
-                       VideoMemSize = (32 << 20);      /*32M */
-                       break;
-               }
-       } else {
-               switch (FBSize) {
-               case 0x00001000:
-                       VideoMemSize = (8 << 20);       /*8M */
-                       break;
-
-               case 0x00002000:
-                       VideoMemSize = (16 << 20);      /*16M */
-                       break;
-
-               case 0x00003000:
-                       VideoMemSize = (32 << 20);      /*32M */
-                       break;
-
-               case 0x00004000:
-                       VideoMemSize = (64 << 20);      /*64M */
-                       break;
-
-               case 0x00005000:
-                       VideoMemSize = (128 << 20);     /*128M */
-                       break;
-
-               case 0x00006000:
-                       VideoMemSize = (256 << 20);     /*256M */
-                       break;
-
-               case 0x00007000:        /* Only on VX855/875 */
-                       VideoMemSize = (512 << 20);     /*512M */
-                       break;
-
-               default:
-                       VideoMemSize = (32 << 20);      /*32M */
-                       break;
-               }
-       }
-
-       return VideoMemSize;
-}
 
 void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
                                        *p_gfx_dpa_setting)
index 12ef32d..a109de3 100644 (file)
 
 #include "viamode.h"
 #include "global.h"
+#include "via_modesetting.h"
+
+#define viafb_read_reg(p, i)                   via_read_reg(p, i)
+#define viafb_write_reg(i, p, d)               via_write_reg(p, i, d)
+#define viafb_write_reg_mask(i, p, d, m)       via_write_reg_mask(p, i, d, m)
 
 /***************************************************
 * Definition IGA1 Design Method of CRTC Registers *
@@ -823,8 +828,8 @@ struct iga2_crtc_timing {
 };
 
 /* device ID */
-#define CLE266              0x3123
-#define KM400               0x3205
+#define CLE266_FUNCTION3    0x3123
+#define KM400_FUNCTION3     0x3205
 #define CN400_FUNCTION2     0x2259
 #define CN400_FUNCTION3     0x3259
 /* support VT3314 chipset */
@@ -870,7 +875,6 @@ extern int viafb_LCD_ON;
 extern int viafb_DVI_ON;
 extern int viafb_hotplug;
 
-void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask);
 void viafb_set_output_path(int device, int set_iga,
        int output_interface);
 
@@ -885,8 +889,6 @@ void viafb_crt_disable(void);
 void viafb_crt_enable(void);
 void init_ad9389(void);
 /* Access I/O Function */
-void viafb_write_reg(u8 index, u16 io_port, u8 data);
-u8 viafb_read_reg(int io_port, u8 index);
 void viafb_lock_crt(void);
 void viafb_unlock_crt(void);
 void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga);
@@ -900,20 +902,14 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
        struct VideoModeTable *vmode_tbl1, int video_bpp1);
 void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
        struct VideoModeTable *vmode_tbl);
-void viafb_init_chip_info(struct pci_dev *pdev,
-                         const struct pci_device_id *pdi);
+void viafb_init_chip_info(int chip_type);
 void viafb_init_dac(int set_iga);
 int viafb_get_pixclock(int hres, int vres, int vmode_refresh);
 int viafb_get_refresh(int hres, int vres, u32 float_refresh);
 void viafb_update_device_setting(int hres, int vres, int bpp,
                           int vmode_refresh, int flag);
 
-int viafb_get_fb_size_from_pci(void);
 void viafb_set_iga_path(void);
-void viafb_set_primary_address(u32 addr);
-void viafb_set_secondary_address(u32 addr);
-void viafb_set_primary_pitch(u32 pitch);
-void viafb_set_secondary_pitch(u32 pitch);
 void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue);
 void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue);
 void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len);
index de89980..c430fa2 100644 (file)
@@ -75,7 +75,7 @@
 /*SAMM operation flag*/
 #define OP_SAMM            0x80
 
-#define LCD_PANEL_ID_MAXIMUM   22
+#define LCD_PANEL_ID_MAXIMUM   23
 
 #define STATE_ON            0x1
 #define STATE_OFF           0x0
index 1b1ccdc..2ab0f15 100644 (file)
@@ -18,7 +18,8 @@
  * Foundation, Inc.,
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
-
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
 #include "global.h"
 #include "lcdtbl.h"
 
@@ -172,18 +173,16 @@ static bool lvds_identify_integratedlvds(void)
 
 int viafb_lvds_trasmitter_identify(void)
 {
-       viaparinfo->shared->i2c_stuff.i2c_port = I2CPORTINDEX;
-       if (viafb_lvds_identify_vt1636()) {
-               viaparinfo->chip_info->lvds_chip_info.i2c_port = I2CPORTINDEX;
+       if (viafb_lvds_identify_vt1636(VIA_PORT_31)) {
+               viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31;
                DEBUG_MSG(KERN_INFO
-                         "Found VIA VT1636 LVDS on port i2c 0x31 \n");
+                         "Found VIA VT1636 LVDS on port i2c 0x31\n");
        } else {
-               viaparinfo->shared->i2c_stuff.i2c_port = GPIOPORTINDEX;
-               if (viafb_lvds_identify_vt1636()) {
+               if (viafb_lvds_identify_vt1636(VIA_PORT_2C)) {
                        viaparinfo->chip_info->lvds_chip_info.i2c_port =
-                               GPIOPORTINDEX;
+                               VIA_PORT_2C;
                        DEBUG_MSG(KERN_INFO
-                                 "Found VIA VT1636 LVDS on port gpio 0x2c \n");
+                                 "Found VIA VT1636 LVDS on port gpio 0x2c\n");
                }
        }
 
@@ -398,6 +397,15 @@ static void fp_id_to_vindex(int panel_id)
                viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
                viaparinfo->lvds_setting_info->LCDDithering = 1;
                break;
+       case 0x17:
+               /* OLPC XO-1.5 panel */
+               viaparinfo->lvds_setting_info->lcd_panel_hres = 1200;
+               viaparinfo->lvds_setting_info->lcd_panel_vres = 900;
+               viaparinfo->lvds_setting_info->lcd_panel_id =
+                       LCD_PANEL_IDD_1200X900;
+               viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+               viaparinfo->lvds_setting_info->LCDDithering = 0;
+               break;
        default:
                viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
                viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
@@ -412,9 +420,8 @@ static int lvds_register_read(int index)
 {
        u8 data;
 
-       viaparinfo->shared->i2c_stuff.i2c_port = GPIOPORTINDEX;
-       viafb_i2c_readbyte((u8) viaparinfo->chip_info->
-           lvds_chip_info.lvds_chip_slave_addr,
+       viafb_i2c_readbyte(VIA_PORT_2C,
+                       (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr,
                        (u8) index, &data);
        return data;
 }
index 071f47c..9762ec6 100644 (file)
@@ -60,6 +60,8 @@
 #define     LCD_PANEL_IDB_1360X768     0x0B
 /* Resolution: 480x640,  Channel: single, Dithering: Enable */
 #define     LCD_PANEL_IDC_480X640      0x0C
+/* Resolution: 1200x900,  Channel: single, Dithering: Disable */
+#define     LCD_PANEL_IDD_1200X900      0x0D
 
 
 extern int viafb_LCD2_ON;
index d55aaa7..7f0de7f 100644 (file)
 /* Video Memory Size */
 #define VIDEO_MEMORY_SIZE_16M    0x1000000
 
-/* standard VGA IO port
-*/
-#define VIARMisc    0x3CC
-#define VIAWMisc    0x3C2
-#define VIAStatus   0x3DA
-#define VIACR       0x3D4
-#define VIASR       0x3C4
-#define VIAGR       0x3CE
-#define VIAAR       0x3C0
-
+/*
+ * Lengths of the VPIT structure arrays.
+ */
 #define StdCR       0x19
 #define StdSR       0x04
 #define StdGR       0x09
 #define M1200X720_R60_HSP       NEGATIVE
 #define M1200X720_R60_VSP       POSITIVE
 
+/* 1200x900@60 Sync Polarity (DCON) */
+#define M1200X900_R60_HSP       NEGATIVE
+#define M1200X900_R60_VSP       NEGATIVE
+
 /* 1280x600@60 Sync Polarity (GTF Mode) */
 #define M1280x600_R60_HSP       NEGATIVE
 #define M1280x600_R60_VSP       POSITIVE
 #define CLK_52_406M     52406000
 #define CLK_52_977M     52977000
 #define CLK_56_250M     56250000
+#define CLK_57_275M     57275000
 #define CLK_60_466M     60466000
 #define CLK_61_500M     61500000
 #define CLK_65_000M     65000000
 #define VX855_52_406M     0x00580C03
 #define VX855_52_977M     0x00940C05
 #define VX855_56_250M     0x009D0C05
+#define VX855_57_275M     0x009D8C85    /* Used by XO panel */
 #define VX855_60_466M     0x00A90C05
 #define VX855_61_500M     0x00AC0C05
 #define VX855_65_000M     0x006D0C03
 #define RES_1600X1200_60HZ_PIXCLOCK  6172
 #define RES_1600X1200_75HZ_PIXCLOCK  4938
 #define RES_1280X720_60HZ_PIXCLOCK   13426
+#define RES_1200X900_60HZ_PIXCLOCK   17459
 #define RES_1920X1080_60HZ_PIXCLOCK  5787
 #define RES_1400X1050_60HZ_PIXCLOCK  8214
 #define RES_1400X1050_75HZ_PIXCLOCK  6410
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
new file mode 100644 (file)
index 0000000..e8cfe83
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
+ */
+
+/*
+ * Core code for the Via multifunction framebuffer device.
+ */
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
+#include <linux/via-gpio.h>
+#include "global.h"
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+/*
+ * The default port config.
+ */
+static struct via_port_cfg adap_configs[] = {
+       [VIA_PORT_26]   = { VIA_PORT_I2C,  VIA_MODE_OFF, VIASR, 0x26 },
+       [VIA_PORT_31]   = { VIA_PORT_I2C,  VIA_MODE_I2C, VIASR, 0x31 },
+       [VIA_PORT_25]   = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
+       [VIA_PORT_2C]   = { VIA_PORT_GPIO, VIA_MODE_I2C, VIASR, 0x2c },
+       [VIA_PORT_3D]   = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d },
+       { 0, 0, 0, 0 }
+};
+
+/*
+ * We currently only support one viafb device (will there ever be
+ * more than one?), so just declare it globally here.
+ */
+static struct viafb_dev global_dev;
+
+
+/*
+ * Basic register access; spinlock required.
+ */
+static inline void viafb_mmio_write(int reg, u32 v)
+{
+       iowrite32(v, global_dev.engine_mmio + reg);
+}
+
+static inline int viafb_mmio_read(int reg)
+{
+       return ioread32(global_dev.engine_mmio + reg);
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Interrupt management.  We have a single IRQ line for a lot of
+ * different functions, so we need to share it.  The design here
+ * is that we don't want to reimplement the shared IRQ code here;
+ * we also want to avoid having contention for a single handler thread.
+ * So each subdev driver which needs interrupts just requests
+ * them directly from the kernel.  We just have what's needed for
+ * overall access to the interrupt control register.
+ */
+
+/*
+ * Which interrupts are enabled now?
+ */
+static u32 viafb_enabled_ints;
+
+static void viafb_int_init(void)
+{
+       viafb_enabled_ints = 0;
+
+       viafb_mmio_write(VDE_INTERRUPT, 0);
+}
+
+/*
+ * Allow subdevs to ask for specific interrupts to be enabled.  These
+ * functions must be called with reg_lock held
+ */
+void viafb_irq_enable(u32 mask)
+{
+       viafb_enabled_ints |= mask;
+       viafb_mmio_write(VDE_INTERRUPT, viafb_enabled_ints | VDE_I_ENABLE);
+}
+EXPORT_SYMBOL_GPL(viafb_irq_enable);
+
+void viafb_irq_disable(u32 mask)
+{
+       viafb_enabled_ints &= ~mask;
+       if (viafb_enabled_ints == 0)
+               viafb_mmio_write(VDE_INTERRUPT, 0);  /* Disable entirely */
+       else
+               viafb_mmio_write(VDE_INTERRUPT,
+                               viafb_enabled_ints | VDE_I_ENABLE);
+}
+EXPORT_SYMBOL_GPL(viafb_irq_disable);
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Access to the DMA engine.  This currently provides what the camera
+ * driver needs (i.e. outgoing only) but is easily expandable if need
+ * be.
+ */
+
+/*
+ * There are four DMA channels in the vx855.  For now, we only
+ * use one of them, though.  Most of the time, the DMA channel
+ * will be idle, so we keep the IRQ handler unregistered except
+ * when some subsystem has indicated an interest.
+ */
+static int viafb_dma_users;
+static DECLARE_COMPLETION(viafb_dma_completion);
+/*
+ * This mutex protects viafb_dma_users and our global interrupt
+ * registration state; it also serializes access to the DMA
+ * engine.
+ */
+static DEFINE_MUTEX(viafb_dma_lock);
+
+/*
+ * The VX855 DMA descriptor (used for s/g transfers) looks
+ * like this.
+ */
+struct viafb_vx855_dma_descr {
+       u32     addr_low;       /* Low part of phys addr */
+       u32     addr_high;      /* High 12 bits of addr */
+       u32     fb_offset;      /* Offset into FB memory */
+       u32     seg_size;       /* Size, 16-byte units */
+       u32     tile_mode;      /* "tile mode" setting */
+       u32     next_desc_low;  /* Next descriptor addr */
+       u32     next_desc_high;
+       u32     pad;            /* Fill out to 64 bytes */
+};
+
+/*
+ * Flags added to the "next descriptor low" pointers
+ */
+#define VIAFB_DMA_MAGIC                0x01  /* ??? Just has to be there */
+#define VIAFB_DMA_FINAL_SEGMENT 0x02  /* Final segment */
+
+/*
+ * The completion IRQ handler.
+ */
+static irqreturn_t viafb_dma_irq(int irq, void *data)
+{
+       int csr;
+       irqreturn_t ret = IRQ_NONE;
+
+       spin_lock(&global_dev.reg_lock);
+       csr = viafb_mmio_read(VDMA_CSR0);
+       if (csr & VDMA_C_DONE) {
+               viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE);
+               complete(&viafb_dma_completion);
+               ret = IRQ_HANDLED;
+       }
+       spin_unlock(&global_dev.reg_lock);
+       return ret;
+}
+
+/*
+ * Indicate a need for DMA functionality.
+ */
+int viafb_request_dma(void)
+{
+       int ret = 0;
+
+       /*
+        * Only VX855 is supported currently.
+        */
+       if (global_dev.chip_type != UNICHROME_VX855)
+               return -ENODEV;
+       /*
+        * Note the new user and set up our interrupt handler
+        * if need be.
+        */
+       mutex_lock(&viafb_dma_lock);
+       viafb_dma_users++;
+       if (viafb_dma_users == 1) {
+               ret = request_irq(global_dev.pdev->irq, viafb_dma_irq,
+                               IRQF_SHARED, "via-dma", &viafb_dma_users);
+               if (ret)
+                       viafb_dma_users--;
+               else
+                       viafb_irq_enable(VDE_I_DMA0TDEN);
+       }
+       mutex_unlock(&viafb_dma_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(viafb_request_dma);
+
+void viafb_release_dma(void)
+{
+       mutex_lock(&viafb_dma_lock);
+       viafb_dma_users--;
+       if (viafb_dma_users == 0) {
+               viafb_irq_disable(VDE_I_DMA0TDEN);
+               free_irq(global_dev.pdev->irq, &viafb_dma_users);
+       }
+       mutex_unlock(&viafb_dma_lock);
+}
+EXPORT_SYMBOL_GPL(viafb_release_dma);
+
+
+#if 0
+/*
+ * Copy a single buffer from FB memory, synchronously.  This code works
+ * but is not currently used.
+ */
+void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len)
+{
+       unsigned long flags;
+       int csr;
+
+       mutex_lock(&viafb_dma_lock);
+       init_completion(&viafb_dma_completion);
+       /*
+        * Program the controller.
+        */
+       spin_lock_irqsave(&global_dev.reg_lock, flags);
+       viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE);
+       /* Enable ints; must happen after CSR0 write! */
+       viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE);
+       viafb_mmio_write(VDMA_MARL0, (int) (paddr & 0xfffffff0));
+       viafb_mmio_write(VDMA_MARH0, (int) ((paddr >> 28) & 0xfff));
+       /* Data sheet suggests DAR0 should be <<4, but it lies */
+       viafb_mmio_write(VDMA_DAR0, offset);
+       viafb_mmio_write(VDMA_DQWCR0, len >> 4);
+       viafb_mmio_write(VDMA_TMR0, 0);
+       viafb_mmio_write(VDMA_DPRL0, 0);
+       viafb_mmio_write(VDMA_DPRH0, 0);
+       viafb_mmio_write(VDMA_PMR0, 0);
+       csr = viafb_mmio_read(VDMA_CSR0);
+       viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START);
+       spin_unlock_irqrestore(&global_dev.reg_lock, flags);
+       /*
+        * Now we just wait until the interrupt handler says
+        * we're done.
+        */
+       wait_for_completion_interruptible(&viafb_dma_completion);
+       viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */
+       mutex_unlock(&viafb_dma_lock);
+}
+EXPORT_SYMBOL_GPL(viafb_dma_copy_out);
+#endif
+
+/*
+ * Do a scatter/gather DMA copy from FB memory.  You must have done
+ * a successful call to viafb_request_dma() first.
+ */
+int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
+{
+       struct viafb_vx855_dma_descr *descr;
+       void *descrpages;
+       dma_addr_t descr_handle;
+       unsigned long flags;
+       int i;
+       struct scatterlist *sgentry;
+       dma_addr_t nextdesc;
+
+       /*
+        * Get a place to put the descriptors.
+        */
+       descrpages = dma_alloc_coherent(&global_dev.pdev->dev,
+                       nsg*sizeof(struct viafb_vx855_dma_descr),
+                       &descr_handle, GFP_KERNEL);
+       if (descrpages == NULL) {
+               dev_err(&global_dev.pdev->dev, "Unable to get descr page.\n");
+               return -ENOMEM;
+       }
+       mutex_lock(&viafb_dma_lock);
+       /*
+        * Fill them in.
+        */
+       descr = descrpages;
+       nextdesc = descr_handle + sizeof(struct viafb_vx855_dma_descr);
+       for_each_sg(sg, sgentry, nsg, i) {
+               dma_addr_t paddr = sg_dma_address(sgentry);
+               descr->addr_low = paddr & 0xfffffff0;
+               descr->addr_high = ((u64) paddr >> 32) & 0x0fff;
+               descr->fb_offset = offset;
+               descr->seg_size = sg_dma_len(sgentry) >> 4;
+               descr->tile_mode = 0;
+               descr->next_desc_low = (nextdesc&0xfffffff0) | VIAFB_DMA_MAGIC;
+               descr->next_desc_high = ((u64) nextdesc >> 32) & 0x0fff;
+               descr->pad = 0xffffffff;  /* VIA driver does this */
+               offset += sg_dma_len(sgentry);
+               nextdesc += sizeof(struct viafb_vx855_dma_descr);
+               descr++;
+       }
+       descr[-1].next_desc_low = VIAFB_DMA_FINAL_SEGMENT|VIAFB_DMA_MAGIC;
+       /*
+        * Program the engine.
+        */
+       spin_lock_irqsave(&global_dev.reg_lock, flags);
+       init_completion(&viafb_dma_completion);
+       viafb_mmio_write(VDMA_DQWCR0, 0);
+       viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE);
+       viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE | VDMA_MR_CHAIN);
+       viafb_mmio_write(VDMA_DPRL0, descr_handle | VIAFB_DMA_MAGIC);
+       viafb_mmio_write(VDMA_DPRH0,
+                       (((u64)descr_handle >> 32) & 0x0fff) | 0xf0000);
+       (void) viafb_mmio_read(VDMA_CSR0);
+       viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START);
+       spin_unlock_irqrestore(&global_dev.reg_lock, flags);
+       /*
+        * Now we just wait until the interrupt handler says
+        * we're done.  Except that, actually, we need to wait a little
+        * longer: the interrupts seem to jump the gun a little and we
+        * get corrupted frames sometimes.
+        */
+       wait_for_completion_timeout(&viafb_dma_completion, 1);
+       msleep(1);
+       if ((viafb_mmio_read(VDMA_CSR0)&VDMA_C_DONE) == 0)
+               printk(KERN_ERR "VIA DMA timeout!\n");
+       /*
+        * Clean up and we're done.
+        */
+       viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE);
+       viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */
+       mutex_unlock(&viafb_dma_lock);
+       dma_free_coherent(&global_dev.pdev->dev,
+                       nsg*sizeof(struct viafb_vx855_dma_descr), descrpages,
+                       descr_handle);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg);
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Figure out how big our framebuffer memory is.  Kind of ugly,
+ * but evidently we can't trust the information found in the
+ * fbdev configuration area.
+ */
+static u16 via_function3[] = {
+       CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3,
+       CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3,
+       P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3,
+};
+
+/* Get the BIOS-configured framebuffer size from PCI configuration space
+ * of function 3 in the respective chipset */
+static int viafb_get_fb_size_from_pci(int chip_type)
+{
+       int i;
+       u8 offset = 0;
+       u32 FBSize;
+       u32 VideoMemSize;
+
+       /* search for the "FUNCTION3" device in this chipset */
+       for (i = 0; i < ARRAY_SIZE(via_function3); i++) {
+               struct pci_dev *pdev;
+
+               pdev = pci_get_device(PCI_VENDOR_ID_VIA, via_function3[i],
+                                     NULL);
+               if (!pdev)
+                       continue;
+
+               DEBUG_MSG(KERN_INFO "Device ID = %x\n", pdev->device);
+
+               switch (pdev->device) {
+               case CLE266_FUNCTION3:
+               case KM400_FUNCTION3:
+                       offset = 0xE0;
+                       break;
+               case CN400_FUNCTION3:
+               case CN700_FUNCTION3:
+               case CX700_FUNCTION3:
+               case KM800_FUNCTION3:
+               case KM890_FUNCTION3:
+               case P4M890_FUNCTION3:
+               case P4M900_FUNCTION3:
+               case VX800_FUNCTION3:
+               case VX855_FUNCTION3:
+               /*case CN750_FUNCTION3: */
+                       offset = 0xA0;
+                       break;
+               }
+
+               if (!offset)
+                       break;
+
+               pci_read_config_dword(pdev, offset, &FBSize);
+               pci_dev_put(pdev);
+       }
+
+       if (!offset) {
+               printk(KERN_ERR "cannot determine framebuffer size\n");
+               return -EIO;
+       }
+
+       FBSize = FBSize & 0x00007000;
+       DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
+
+       if (chip_type < UNICHROME_CX700) {
+               switch (FBSize) {
+               case 0x00004000:
+                       VideoMemSize = (16 << 20);      /*16M */
+                       break;
+
+               case 0x00005000:
+                       VideoMemSize = (32 << 20);      /*32M */
+                       break;
+
+               case 0x00006000:
+                       VideoMemSize = (64 << 20);      /*64M */
+                       break;
+
+               default:
+                       VideoMemSize = (32 << 20);      /*32M */
+                       break;
+               }
+       } else {
+               switch (FBSize) {
+               case 0x00001000:
+                       VideoMemSize = (8 << 20);       /*8M */
+                       break;
+
+               case 0x00002000:
+                       VideoMemSize = (16 << 20);      /*16M */
+                       break;
+
+               case 0x00003000:
+                       VideoMemSize = (32 << 20);      /*32M */
+                       break;
+
+               case 0x00004000:
+                       VideoMemSize = (64 << 20);      /*64M */
+                       break;
+
+               case 0x00005000:
+                       VideoMemSize = (128 << 20);     /*128M */
+                       break;
+
+               case 0x00006000:
+                       VideoMemSize = (256 << 20);     /*256M */
+                       break;
+
+               case 0x00007000:        /* Only on VX855/875 */
+                       VideoMemSize = (512 << 20);     /*512M */
+                       break;
+
+               default:
+                       VideoMemSize = (32 << 20);      /*32M */
+                       break;
+               }
+       }
+
+       return VideoMemSize;
+}
+
+
+/*
+ * Figure out and map our MMIO regions.
+ */
+static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev)
+{
+       int ret;
+       /*
+        * Hook up to the device registers.  Note that we soldier
+        * on if it fails; the framebuffer can operate (without
+        * acceleration) without this region.
+        */
+       vdev->engine_start = pci_resource_start(vdev->pdev, 1);
+       vdev->engine_len = pci_resource_len(vdev->pdev, 1);
+       vdev->engine_mmio = ioremap_nocache(vdev->engine_start,
+                       vdev->engine_len);
+       if (vdev->engine_mmio == NULL)
+               dev_err(&vdev->pdev->dev,
+                               "Unable to map engine MMIO; operation will be "
+                               "slow and crippled.\n");
+       /*
+        * Map in framebuffer memory.  For now, failure here is
+        * fatal.  Unfortunately, in the absence of significant
+        * vmalloc space, failure here is also entirely plausible.
+        * Eventually we want to move away from mapping this
+        * entire region.
+        */
+       vdev->fbmem_start = pci_resource_start(vdev->pdev, 0);
+       ret = vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type);
+       if (ret < 0)
+               goto out_unmap;
+       vdev->fbmem = ioremap_nocache(vdev->fbmem_start, vdev->fbmem_len);
+       if (vdev->fbmem == NULL) {
+               ret = -ENOMEM;
+               goto out_unmap;
+       }
+       return 0;
+out_unmap:
+       iounmap(vdev->engine_mmio);
+       return ret;
+}
+
+static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev)
+{
+       iounmap(vdev->fbmem);
+       iounmap(vdev->engine_mmio);
+}
+
+/*
+ * Create our subsidiary devices.
+ */
+static struct viafb_subdev_info {
+       char *name;
+       struct platform_device *platdev;
+} viafb_subdevs[] = {
+       {
+               .name = "viafb-gpio",
+       },
+       {
+               .name = "viafb-i2c",
+       }
+};
+#define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)
+
+static int __devinit via_create_subdev(struct viafb_dev *vdev,
+               struct viafb_subdev_info *info)
+{
+       int ret;
+
+       info->platdev = platform_device_alloc(info->name, -1);
+       if (!info->platdev) {
+               dev_err(&vdev->pdev->dev, "Unable to allocate pdev %s\n",
+                       info->name);
+               return -ENOMEM;
+       }
+       info->platdev->dev.parent = &vdev->pdev->dev;
+       info->platdev->dev.platform_data = vdev;
+       ret = platform_device_add(info->platdev);
+       if (ret) {
+               dev_err(&vdev->pdev->dev, "Unable to add pdev %s\n",
+                               info->name);
+               platform_device_put(info->platdev);
+               info->platdev = NULL;
+       }
+       return ret;
+}
+
+static int __devinit via_setup_subdevs(struct viafb_dev *vdev)
+{
+       int i;
+
+       /*
+        * Ignore return values.  Even if some of the devices
+        * fail to be created, we'll still be able to use some
+        * of the rest.
+        */
+       for (i = 0; i < N_SUBDEVS; i++)
+               via_create_subdev(vdev, viafb_subdevs + i);
+       return 0;
+}
+
+static void __devexit via_teardown_subdevs(void)
+{
+       int i;
+
+       for (i = 0; i < N_SUBDEVS; i++)
+               if (viafb_subdevs[i].platdev) {
+                       viafb_subdevs[i].platdev->dev.platform_data = NULL;
+                       platform_device_unregister(viafb_subdevs[i].platdev);
+               }
+}
+
+
+static int __devinit via_pci_probe(struct pci_dev *pdev,
+               const struct pci_device_id *ent)
+{
+       int ret;
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+       /*
+        * Global device initialization.
+        */
+       memset(&global_dev, 0, sizeof(global_dev));
+       global_dev.pdev = pdev;
+       global_dev.chip_type = ent->driver_data;
+       global_dev.port_cfg = adap_configs;
+       spin_lock_init(&global_dev.reg_lock);
+       ret = via_pci_setup_mmio(&global_dev);
+       if (ret)
+               goto out_disable;
+       /*
+        * Set up interrupts and create our subdevices.  Continue even if
+        * some things fail.
+        */
+       viafb_int_init();
+       via_setup_subdevs(&global_dev);
+       /*
+        * Set up the framebuffer device
+        */
+       ret = via_fb_pci_probe(&global_dev);
+       if (ret)
+               goto out_subdevs;
+       return 0;
+
+out_subdevs:
+       via_teardown_subdevs();
+       via_pci_teardown_mmio(&global_dev);
+out_disable:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void __devexit via_pci_remove(struct pci_dev *pdev)
+{
+       via_teardown_subdevs();
+       via_fb_pci_remove(pdev);
+       via_pci_teardown_mmio(&global_dev);
+       pci_disable_device(pdev);
+}
+
+
+static struct pci_device_id via_pci_table[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
+         .driver_data = UNICHROME_CLE266 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
+         .driver_data = UNICHROME_PM800 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
+         .driver_data = UNICHROME_K400 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID),
+         .driver_data = UNICHROME_K800 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
+         .driver_data = UNICHROME_CN700 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
+         .driver_data = UNICHROME_K8M890 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID),
+         .driver_data = UNICHROME_CX700 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
+         .driver_data = UNICHROME_P4M900 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID),
+         .driver_data = UNICHROME_CN750 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID),
+         .driver_data = UNICHROME_VX800 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),
+         .driver_data = UNICHROME_VX855 },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, via_pci_table);
+
+static struct pci_driver via_driver = {
+       .name           = "viafb",
+       .id_table       = via_pci_table,
+       .probe          = via_pci_probe,
+       .remove         = __devexit_p(via_pci_remove),
+};
+
+static int __init via_core_init(void)
+{
+       int ret;
+
+       ret = viafb_init();
+       if (ret)
+               return ret;
+       viafb_i2c_init();
+       viafb_gpio_init();
+       return pci_register_driver(&via_driver);
+}
+
+static void __exit via_core_exit(void)
+{
+       pci_unregister_driver(&via_driver);
+       viafb_gpio_exit();
+       viafb_i2c_exit();
+       viafb_exit();
+}
+
+module_init(via_core_init);
+module_exit(via_core_exit);
diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c
new file mode 100644 (file)
index 0000000..595516a
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Support for viafb GPIO ports.
+ *
+ * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
+ * Distributable under version 2 of the GNU General Public License.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/via-core.h>
+#include <linux/via-gpio.h>
+
+/*
+ * The ports we know about.  Note that the port-25 gpios are not
+ * mentioned in the datasheet.
+ */
+
+struct viafb_gpio {
+       char *vg_name;  /* Data sheet name */
+       u16 vg_io_port;
+       u8  vg_port_index;
+       int  vg_mask_shift;
+};
+
+static struct viafb_gpio viafb_all_gpios[] = {
+       {
+               .vg_name = "VGPIO0",  /* Guess - not in datasheet */
+               .vg_io_port = VIASR,
+               .vg_port_index = 0x25,
+               .vg_mask_shift = 1
+       },
+       {
+               .vg_name = "VGPIO1",
+               .vg_io_port = VIASR,
+               .vg_port_index = 0x25,
+               .vg_mask_shift = 0
+       },
+       {
+               .vg_name = "VGPIO2",  /* aka DISPCLKI0 */
+               .vg_io_port = VIASR,
+               .vg_port_index = 0x2c,
+               .vg_mask_shift = 1
+       },
+       {
+               .vg_name = "VGPIO3",  /* aka DISPCLKO0 */
+               .vg_io_port = VIASR,
+               .vg_port_index = 0x2c,
+               .vg_mask_shift = 0
+       },
+       {
+               .vg_name = "VGPIO4",  /* DISPCLKI1 */
+               .vg_io_port = VIASR,
+               .vg_port_index = 0x3d,
+               .vg_mask_shift = 1
+       },
+       {
+               .vg_name = "VGPIO5",  /* DISPCLKO1 */
+               .vg_io_port = VIASR,
+               .vg_port_index = 0x3d,
+               .vg_mask_shift = 0
+       },
+};
+
+#define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios)
+
+/*
+ * This structure controls the active GPIOs, which may be a subset
+ * of those which are known.
+ */
+
+struct viafb_gpio_cfg {
+       struct gpio_chip gpio_chip;
+       struct viafb_dev *vdev;
+       struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS];
+       char *gpio_names[VIAFB_NUM_GPIOS];
+};
+
+/*
+ * GPIO access functions
+ */
+static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
+                        int value)
+{
+       struct viafb_gpio_cfg *cfg = container_of(chip,
+                                                 struct viafb_gpio_cfg,
+                                                 gpio_chip);
+       u8 reg;
+       struct viafb_gpio *gpio;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
+       gpio = cfg->active_gpios[nr];
+       reg = via_read_reg(VIASR, gpio->vg_port_index);
+       reg |= 0x40 << gpio->vg_mask_shift;  /* output enable */
+       if (value)
+               reg |= 0x10 << gpio->vg_mask_shift;
+       else
+               reg &= ~(0x10 << gpio->vg_mask_shift);
+       via_write_reg(VIASR, gpio->vg_port_index, reg);
+       spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
+}
+
+static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr,
+                           int value)
+{
+       via_gpio_set(chip, nr, value);
+       return 0;
+}
+
+/*
+ * Set the input direction.  I'm not sure this is right; we should
+ * be able to do input without disabling output.
+ */
+static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
+{
+       struct viafb_gpio_cfg *cfg = container_of(chip,
+                                                 struct viafb_gpio_cfg,
+                                                 gpio_chip);
+       struct viafb_gpio *gpio;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
+       gpio = cfg->active_gpios[nr];
+       via_write_reg_mask(VIASR, gpio->vg_port_index, 0,
+                       0x40 << gpio->vg_mask_shift);
+       spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
+       return 0;
+}
+
+static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
+{
+       struct viafb_gpio_cfg *cfg = container_of(chip,
+                                                 struct viafb_gpio_cfg,
+                                                 gpio_chip);
+       u8 reg;
+       struct viafb_gpio *gpio;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
+       gpio = cfg->active_gpios[nr];
+       reg = via_read_reg(VIASR, gpio->vg_port_index);
+       spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
+       return reg & (0x04 << gpio->vg_mask_shift);
+}
+
+
+static struct viafb_gpio_cfg gpio_config = {
+       .gpio_chip = {
+               .label = "VIAFB onboard GPIO",
+               .owner = THIS_MODULE,
+               .direction_output = via_gpio_dir_out,
+               .set = via_gpio_set,
+               .direction_input = via_gpio_dir_input,
+               .get = via_gpio_get,
+               .base = -1,
+               .ngpio = 0,
+               .can_sleep = 0
+       }
+};
+
+/*
+ * Manage the software enable bit.
+ */
+static void viafb_gpio_enable(struct viafb_gpio *gpio)
+{
+       via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02);
+}
+
+static void viafb_gpio_disable(struct viafb_gpio *gpio)
+{
+       via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
+}
+
+/*
+ * Look up a specific gpio and return the number it was assigned.
+ */
+int viafb_gpio_lookup(const char *name)
+{
+       int i;
+
+       for (i = 0; i < gpio_config.gpio_chip.ngpio; i++)
+               if (!strcmp(name, gpio_config.active_gpios[i]->vg_name))
+                       return gpio_config.gpio_chip.base + i;
+       return -1;
+}
+EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
+
+/*
+ * Platform device stuff.
+ */
+static __devinit int viafb_gpio_probe(struct platform_device *platdev)
+{
+       struct viafb_dev *vdev = platdev->dev.platform_data;
+       struct via_port_cfg *port_cfg = vdev->port_cfg;
+       int i, ngpio = 0, ret;
+       struct viafb_gpio *gpio;
+       unsigned long flags;
+
+       /*
+        * Set up entries for all GPIOs which have been configured to
+        * operate as such (as opposed to as i2c ports).
+        */
+       for (i = 0; i < VIAFB_NUM_PORTS; i++) {
+               if (port_cfg[i].mode != VIA_MODE_GPIO)
+                       continue;
+               for (gpio = viafb_all_gpios;
+                    gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
+                       if (gpio->vg_port_index == port_cfg[i].ioport_index) {
+                               gpio_config.active_gpios[ngpio] = gpio;
+                               gpio_config.gpio_names[ngpio] = gpio->vg_name;
+                               ngpio++;
+                       }
+       }
+       gpio_config.gpio_chip.ngpio = ngpio;
+       gpio_config.gpio_chip.names = gpio_config.gpio_names;
+       gpio_config.vdev = vdev;
+       if (ngpio == 0) {
+               printk(KERN_INFO "viafb: no GPIOs configured\n");
+               return 0;
+       }
+       /*
+        * Enable the ports.  They come in pairs, with a single
+        * enable bit for both.
+        */
+       spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
+       for (i = 0; i < ngpio; i += 2)
+               viafb_gpio_enable(gpio_config.active_gpios[i]);
+       spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
+       /*
+        * Get registered.
+        */
+       gpio_config.gpio_chip.base = -1;  /* Dynamic */
+       ret = gpiochip_add(&gpio_config.gpio_chip);
+       if (ret) {
+               printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
+               gpio_config.gpio_chip.ngpio = 0;
+       }
+       return ret;
+}
+
+
+static int viafb_gpio_remove(struct platform_device *platdev)
+{
+       unsigned long flags;
+       int ret = 0, i;
+
+       /*
+        * Get unregistered.
+        */
+       if (gpio_config.gpio_chip.ngpio > 0) {
+               ret = gpiochip_remove(&gpio_config.gpio_chip);
+               if (ret) { /* Somebody still using it? */
+                       printk(KERN_ERR "Viafb: GPIO remove failed\n");
+                       return ret;
+               }
+       }
+       /*
+        * Disable the ports.
+        */
+       spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
+       for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
+               viafb_gpio_disable(gpio_config.active_gpios[i]);
+       gpio_config.gpio_chip.ngpio = 0;
+       spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
+       return ret;
+}
+
+static struct platform_driver via_gpio_driver = {
+       .driver = {
+               .name = "viafb-gpio",
+       },
+       .probe = viafb_gpio_probe,
+       .remove = viafb_gpio_remove,
+};
+
+int viafb_gpio_init(void)
+{
+       return platform_driver_register(&via_gpio_driver);
+}
+
+void viafb_gpio_exit(void)
+{
+       platform_driver_unregister(&via_gpio_driver);
+}
index 15543e9..da9e4ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
  * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
 
  * This program is free software; you can redistribute it and/or
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include "global.h"
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
+
+/*
+ * There can only be one set of these, so there's no point in having
+ * them be dynamically allocated...
+ */
+#define VIAFB_NUM_I2C          5
+static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C];
+struct viafb_dev *i2c_vdev;  /* Passed in from core */
 
 static void via_i2c_setscl(void *data, int state)
 {
        u8 val;
-       struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+       struct via_port_cfg *adap_data = data;
+       unsigned long flags;
 
-       val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
+       spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+       val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
        if (state)
                val |= 0x20;
        else
                val &= ~0x20;
-       switch (via_i2c_chan->i2c_port) {
-       case I2CPORTINDEX:
+       switch (adap_data->type) {
+       case VIA_PORT_I2C:
                val |= 0x01;
                break;
-       case GPIOPORTINDEX:
+       case VIA_PORT_GPIO:
                val |= 0x80;
                break;
        default:
-               DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
+               printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
        }
-       viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
+       via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
+       spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
 }
 
 static int via_i2c_getscl(void *data)
 {
-       struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+       struct via_port_cfg *adap_data = data;
+       unsigned long flags;
+       int ret = 0;
 
-       if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x08)
-               return 1;
-       return 0;
+       spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+       if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08)
+               ret = 1;
+       spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
+       return ret;
 }
 
 static int via_i2c_getsda(void *data)
 {
-       struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+       struct via_port_cfg *adap_data = data;
+       unsigned long flags;
+       int ret = 0;
 
-       if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x04)
-               return 1;
-       return 0;
+       spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+       if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04)
+               ret = 1;
+       spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
+       return ret;
 }
 
 static void via_i2c_setsda(void *data, int state)
 {
        u8 val;
-       struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+       struct via_port_cfg *adap_data = data;
+       unsigned long flags;
 
-       val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
+       spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+       val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
        if (state)
                val |= 0x10;
        else
                val &= ~0x10;
-       switch (via_i2c_chan->i2c_port) {
-       case I2CPORTINDEX:
+       switch (adap_data->type) {
+       case VIA_PORT_I2C:
                val |= 0x01;
                break;
-       case GPIOPORTINDEX:
+       case VIA_PORT_GPIO:
                val |= 0x40;
                break;
        default:
-               DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
+               printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
        }
-       viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
+       via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
+       spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
 }
 
-int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata)
+int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata)
 {
        u8 mm1[] = {0x00};
        struct i2c_msg msgs[2];
 
+       if (!via_i2c_par[adap].is_active)
+               return -ENODEV;
        *pdata = 0;
        msgs[0].flags = 0;
        msgs[1].flags = I2C_M_RD;
@@ -97,81 +126,144 @@ int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata)
        mm1[0] = index;
        msgs[0].len = 1; msgs[1].len = 1;
        msgs[0].buf = mm1; msgs[1].buf = pdata;
-       i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, msgs, 2);
-
-       return 0;
+       return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
 }
 
-int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data)
+int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data)
 {
        u8 msg[2] = { index, data };
        struct i2c_msg msgs;
 
+       if (!via_i2c_par[adap].is_active)
+               return -ENODEV;
        msgs.flags = 0;
        msgs.addr = slave_addr / 2;
        msgs.len = 2;
        msgs.buf = msg;
-       return i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, &msgs, 1);
+       return i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1);
 }
 
-int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len)
+int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len)
 {
        u8 mm1[] = {0x00};
        struct i2c_msg msgs[2];
 
+       if (!via_i2c_par[adap].is_active)
+               return -ENODEV;
        msgs[0].flags = 0;
        msgs[1].flags = I2C_M_RD;
        msgs[0].addr = msgs[1].addr = slave_addr / 2;
        mm1[0] = index;
        msgs[0].len = 1; msgs[1].len = buff_len;
        msgs[0].buf = mm1; msgs[1].buf = buff;
-       i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, msgs, 2);
-       return 0;
+       return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
 }
 
-int viafb_create_i2c_bus(void *viapar)
+/*
+ * Allow other viafb subdevices to look up a specific adapter
+ * by port name.
+ */
+struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which)
 {
-       int ret;
-       struct via_i2c_stuff *i2c_stuff =
-               &((struct viafb_par *)viapar)->shared->i2c_stuff;
-
-       strcpy(i2c_stuff->adapter.name, "via_i2c");
-       i2c_stuff->i2c_port = 0x0;
-       i2c_stuff->adapter.owner = THIS_MODULE;
-       i2c_stuff->adapter.id = 0x01FFFF;
-       i2c_stuff->adapter.class = 0;
-       i2c_stuff->adapter.algo_data = &i2c_stuff->algo;
-       i2c_stuff->adapter.dev.parent = NULL;
-       i2c_stuff->algo.setsda = via_i2c_setsda;
-       i2c_stuff->algo.setscl = via_i2c_setscl;
-       i2c_stuff->algo.getsda = via_i2c_getsda;
-       i2c_stuff->algo.getscl = via_i2c_getscl;
-       i2c_stuff->algo.udelay = 40;
-       i2c_stuff->algo.timeout = 20;
-       i2c_stuff->algo.data = i2c_stuff;
-
-       i2c_set_adapdata(&i2c_stuff->adapter, i2c_stuff);
+       struct via_i2c_stuff *stuff = &via_i2c_par[which];
 
-       /* Raise SCL and SDA */
-       i2c_stuff->i2c_port = I2CPORTINDEX;
-       via_i2c_setsda(i2c_stuff, 1);
-       via_i2c_setscl(i2c_stuff, 1);
+       return &stuff->adapter;
+}
+EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter);
 
-       i2c_stuff->i2c_port = GPIOPORTINDEX;
-       via_i2c_setsda(i2c_stuff, 1);
-       via_i2c_setscl(i2c_stuff, 1);
-       udelay(20);
 
-       ret = i2c_bit_add_bus(&i2c_stuff->adapter);
-       if (ret == 0)
-               DEBUG_MSG("I2C bus %s registered.\n", i2c_stuff->adapter.name);
+static int create_i2c_bus(struct i2c_adapter *adapter,
+                         struct i2c_algo_bit_data *algo,
+                         struct via_port_cfg *adap_cfg,
+                         struct pci_dev *pdev)
+{
+       algo->setsda = via_i2c_setsda;
+       algo->setscl = via_i2c_setscl;
+       algo->getsda = via_i2c_getsda;
+       algo->getscl = via_i2c_getscl;
+       algo->udelay = 40;
+       algo->timeout = 20;
+       algo->data = adap_cfg;
+
+       sprintf(adapter->name, "viafb i2c io_port idx 0x%02x",
+               adap_cfg->ioport_index);
+       adapter->owner = THIS_MODULE;
+       adapter->id = 0x01FFFF;
+       adapter->class = I2C_CLASS_DDC;
+       adapter->algo_data = algo;
+       if (pdev)
+               adapter->dev.parent = &pdev->dev;
        else
-               DEBUG_MSG("Failed to register I2C bus %s.\n",
-                       i2c_stuff->adapter.name);
-       return ret;
+               adapter->dev.parent = NULL;
+       /* i2c_set_adapdata(adapter, adap_cfg); */
+
+       /* Raise SCL and SDA */
+       via_i2c_setsda(adap_cfg, 1);
+       via_i2c_setscl(adap_cfg, 1);
+       udelay(20);
+
+       return i2c_bit_add_bus(adapter);
+}
+
+static int viafb_i2c_probe(struct platform_device *platdev)
+{
+       int i, ret;
+       struct via_port_cfg *configs;
+
+       i2c_vdev = platdev->dev.platform_data;
+       configs = i2c_vdev->port_cfg;
+
+       for (i = 0; i < VIAFB_NUM_PORTS; i++) {
+               struct via_port_cfg *adap_cfg = configs++;
+               struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
+
+               i2c_stuff->is_active = 0;
+               if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C)
+                       continue;
+               ret = create_i2c_bus(&i2c_stuff->adapter,
+                                    &i2c_stuff->algo, adap_cfg,
+                               NULL); /* FIXME: PCIDEV */
+               if (ret < 0) {
+                       printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n",
+                               i, ret);
+                       continue;  /* Still try to make the rest */
+               }
+               i2c_stuff->is_active = 1;
+       }
+
+       return 0;
+}
+
+static int viafb_i2c_remove(struct platform_device *platdev)
+{
+       int i;
+
+       for (i = 0; i < VIAFB_NUM_PORTS; i++) {
+               struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
+               /*
+                * Only remove those entries in the array that we've
+                * actually used (and thus initialized algo_data)
+                */
+               if (i2c_stuff->is_active)
+                       i2c_del_adapter(&i2c_stuff->adapter);
+       }
+       return 0;
+}
+
+static struct platform_driver via_i2c_driver = {
+       .driver = {
+               .name = "viafb-i2c",
+       },
+       .probe = viafb_i2c_probe,
+       .remove = viafb_i2c_remove,
+};
+
+int viafb_i2c_init(void)
+{
+       return platform_driver_register(&via_i2c_driver);
 }
 
-void viafb_delete_i2c_buss(void *par)
+void viafb_i2c_exit(void)
 {
-       i2c_del_adapter(&((struct viafb_par *)par)->shared->i2c_stuff.adapter);
+       platform_driver_unregister(&via_i2c_driver);
 }
diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c
new file mode 100644 (file)
index 0000000..3cddcff
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ * basic modesetting functions
+ */
+
+#include <linux/kernel.h>
+#include <linux/via-core.h>
+#include "via_modesetting.h"
+#include "share.h"
+#include "debug.h"
+
+void via_set_primary_address(u32 addr)
+{
+       DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr);
+       via_write_reg(VIACR, 0x0D, addr & 0xFF);
+       via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF);
+       via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF);
+       via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F);
+}
+
+void via_set_secondary_address(u32 addr)
+{
+       DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr);
+       /* secondary display supports only quadword aligned memory */
+       via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE);
+       via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF);
+       via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF);
+       via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07);
+}
+
+void via_set_primary_pitch(u32 pitch)
+{
+       DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch);
+       /* spec does not say that first adapter skips 3 bits but old
+        * code did it and seems to be reasonable in analogy to 2nd adapter
+        */
+       pitch = pitch >> 3;
+       via_write_reg(VIACR, 0x13, pitch & 0xFF);
+       via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0);
+}
+
+void via_set_secondary_pitch(u32 pitch)
+{
+       DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch);
+       pitch = pitch >> 3;
+       via_write_reg(VIACR, 0x66, pitch & 0xFF);
+       via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03);
+       via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80);
+}
+
+void via_set_primary_color_depth(u8 depth)
+{
+       u8 value;
+
+       DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth);
+       switch (depth) {
+       case 8:
+               value = 0x00;
+               break;
+       case 15:
+               value = 0x04;
+               break;
+       case 16:
+               value = 0x14;
+               break;
+       case 24:
+               value = 0x0C;
+               break;
+       case 30:
+               value = 0x08;
+               break;
+       default:
+               printk(KERN_WARNING "via_set_primary_color_depth: "
+                       "Unsupported depth: %d\n", depth);
+               return;
+       }
+
+       via_write_reg_mask(VIASR, 0x15, value, 0x1C);
+}
+
+void via_set_secondary_color_depth(u8 depth)
+{
+       u8 value;
+
+       DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth);
+       switch (depth) {
+       case 8:
+               value = 0x00;
+               break;
+       case 16:
+               value = 0x40;
+               break;
+       case 24:
+               value = 0xC0;
+               break;
+       case 30:
+               value = 0x80;
+               break;
+       default:
+               printk(KERN_WARNING "via_set_secondary_color_depth: "
+                       "Unsupported depth: %d\n", depth);
+               return;
+       }
+
+       via_write_reg_mask(VIACR, 0x67, value, 0xC0);
+}
diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h
new file mode 100644 (file)
index 0000000..ae35cfd
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ * basic modesetting functions
+ */
+
+#ifndef __VIA_MODESETTING_H__
+#define __VIA_MODESETTING_H__
+
+#include <linux/types.h>
+
+void via_set_primary_address(u32 addr);
+void via_set_secondary_address(u32 addr);
+void via_set_primary_pitch(u32 pitch);
+void via_set_secondary_pitch(u32 pitch);
+void via_set_primary_color_depth(u8 depth);
+void via_set_secondary_color_depth(u8 depth);
+
+#endif /* __VIA_MODESETTING_H__ */
index aefdeee..d05ccb6 100644 (file)
@@ -19,6 +19,7 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/via-core.h>
 #include "global.h"
 
 void viafb_get_device_support_state(u32 *support_state)
index 777b38a..2bc40e6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
  * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
 
  * This program is free software; you can redistribute it and/or
@@ -23,8 +23,9 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
-#define _MASTER_FILE
+#include <linux/via-core.h>
 
+#define _MASTER_FILE
 #include "global.h"
 
 static char *viafb_name = "Via";
@@ -221,7 +222,7 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
        /* Adjust var according to our driver's own table */
        viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry);
        if (info->var.accel_flags & FB_ACCELF_TEXT &&
-               !ppar->shared->engine_mmio)
+               !ppar->shared->vdev->engine_mmio)
                info->var.accel_flags = 0;
 
        return 0;
@@ -317,12 +318,12 @@ static int viafb_pan_display(struct fb_var_screeninfo *var,
 
        DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
        if (!viafb_dual_fb) {
-               viafb_set_primary_address(vram_addr);
-               viafb_set_secondary_address(vram_addr);
+               via_set_primary_address(vram_addr);
+               via_set_secondary_address(vram_addr);
        } else if (viapar->iga_path == IGA1)
-               viafb_set_primary_address(vram_addr);
+               via_set_primary_address(vram_addr);
        else
-               viafb_set_secondary_address(vram_addr);
+               via_set_secondary_address(vram_addr);
 
        return 0;
 }
@@ -696,7 +697,7 @@ static void viafb_fillrect(struct fb_info *info,
                rop = 0xF0;
 
        DEBUG_MSG(KERN_DEBUG "viafb 2D engine: fillrect\n");
-       if (shared->hw_bitblt(shared->engine_mmio, VIA_BITBLT_FILL,
+       if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_FILL,
                rect->width, rect->height, info->var.bits_per_pixel,
                viapar->vram_addr, info->fix.line_length, rect->dx, rect->dy,
                NULL, 0, 0, 0, 0, fg_color, 0, rop))
@@ -718,7 +719,7 @@ static void viafb_copyarea(struct fb_info *info,
                return;
 
        DEBUG_MSG(KERN_DEBUG "viafb 2D engine: copyarea\n");
-       if (shared->hw_bitblt(shared->engine_mmio, VIA_BITBLT_COLOR,
+       if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_COLOR,
                area->width, area->height, info->var.bits_per_pixel,
                viapar->vram_addr, info->fix.line_length, area->dx, area->dy,
                NULL, viapar->vram_addr, info->fix.line_length,
@@ -755,7 +756,7 @@ static void viafb_imageblit(struct fb_info *info,
                op = VIA_BITBLT_COLOR;
 
        DEBUG_MSG(KERN_DEBUG "viafb 2D engine: imageblit\n");
-       if (shared->hw_bitblt(shared->engine_mmio, op,
+       if (shared->hw_bitblt(shared->vdev->engine_mmio, op,
                image->width, image->height, info->var.bits_per_pixel,
                viapar->vram_addr, info->fix.line_length, image->dx, image->dy,
                (u32 *)image->data, 0, 0, 0, 0, fg_color, bg_color, 0))
@@ -765,7 +766,7 @@ static void viafb_imageblit(struct fb_info *info,
 static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
        struct viafb_par *viapar = info->par;
-       void __iomem *engine = viapar->shared->engine_mmio;
+       void __iomem *engine = viapar->shared->vdev->engine_mmio;
        u32 temp, xx, yy, bg_color = 0, fg_color = 0,
                chip_name = viapar->shared->chip_info.gfx_chip_name;
        int i, j = 0, cur_size = 64;
@@ -1018,8 +1019,8 @@ static void viafb_set_device(struct device_t active_dev)
                viafb_SAMM_ON = active_dev.samm;
        viafb_primary_dev = active_dev.primary_dev;
 
-       viafb_set_primary_address(0);
-       viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
+       via_set_primary_address(0);
+       via_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
        viafb_set_iga_path();
 }
 
@@ -1165,8 +1166,9 @@ static int apply_device_setting(struct viafb_ioctl_setting setting_info,
                        if (viafb_SAMM_ON)
                                viafb_primary_dev = setting_info.primary_device;
 
-                       viafb_set_primary_address(0);
-                       viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
+                       via_set_primary_address(0);
+                       via_set_secondary_address(viafb_SAMM_ON ?
+                               viafb_second_offset : 0);
                        viafb_set_iga_path();
                }
                need_set_mode = 1;
@@ -1325,6 +1327,8 @@ static void parse_dvi_port(void)
                  output_interface);
 }
 
+#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
+
 /*
  * The proc filesystem read/write function, a simple proc implement to
  * get/set the value of DPA  DVP0,   DVP0DataDriving,  DVP0ClockDriving, DVP1,
@@ -1701,16 +1705,21 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
 }
 static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
 {
-       /* no problem if it was not registered */
+       struct chip_information *chip_info = &viaparinfo->shared->chip_info;
+
        remove_proc_entry("dvp0", viafb_entry);/* parent dir */
        remove_proc_entry("dvp1", viafb_entry);
        remove_proc_entry("dfph", viafb_entry);
        remove_proc_entry("dfpl", viafb_entry);
-       remove_proc_entry("vt1636", viafb_entry);
-       remove_proc_entry("vt1625", viafb_entry);
+       if (chip_info->lvds_chip_info.lvds_chip_name == VT1636_LVDS
+               || chip_info->lvds_chip_info2.lvds_chip_name == VT1636_LVDS)
+               remove_proc_entry("vt1636", viafb_entry);
+
        remove_proc_entry("viafb", NULL);
 }
 
+#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
+
 static int parse_mode(const char *str, u32 *xres, u32 *yres)
 {
        char *ptr;
@@ -1732,12 +1741,13 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
        return 0;
 }
 
-static int __devinit via_pci_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
+
+int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
 {
        u32 default_xres, default_yres;
        struct VideoModeTable *vmode_entry;
        struct fb_var_screeninfo default_var;
+       int rc;
        u32 viafb_par_length;
 
        DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");
@@ -1749,14 +1759,15 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
        */
        viafbinfo = framebuffer_alloc(viafb_par_length +
                ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8),
-               &pdev->dev);
+               &vdev->pdev->dev);
        if (!viafbinfo) {
                printk(KERN_ERR"Could not allocate memory for viafb_info.\n");
-               return -ENODEV;
+               return -ENOMEM;
        }
 
        viaparinfo = (struct viafb_par *)viafbinfo->par;
        viaparinfo->shared = viafbinfo->par + viafb_par_length;
+       viaparinfo->shared->vdev = vdev;
        viaparinfo->vram_addr = 0;
        viaparinfo->tmds_setting_info = &viaparinfo->shared->tmds_setting_info;
        viaparinfo->lvds_setting_info = &viaparinfo->shared->lvds_setting_info;
@@ -1774,23 +1785,20 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
        if (!viafb_SAMM_ON)
                viafb_dual_fb = 0;
 
-       /* Set up I2C bus stuff */
-       viafb_create_i2c_bus(viaparinfo);
-
-       viafb_init_chip_info(pdev, ent);
-       viaparinfo->fbmem = pci_resource_start(pdev, 0);
-       viaparinfo->memsize = viafb_get_fb_size_from_pci();
+       viafb_init_chip_info(vdev->chip_type);
+       /*
+        * The framebuffer will have been successfully mapped by
+        * the core (or we'd not be here), but we still need to
+        * set up our own accounting.
+        */
+       viaparinfo->fbmem = vdev->fbmem_start;
+       viaparinfo->memsize = vdev->fbmem_len;
        viaparinfo->fbmem_free = viaparinfo->memsize;
        viaparinfo->fbmem_used = 0;
-       viafbinfo->screen_base = ioremap_nocache(viaparinfo->fbmem,
-               viaparinfo->memsize);
-       if (!viafbinfo->screen_base) {
-               printk(KERN_INFO "ioremap failed\n");
-               return -ENOMEM;
-       }
+       viafbinfo->screen_base = vdev->fbmem;
 
-       viafbinfo->fix.mmio_start = pci_resource_start(pdev, 1);
-       viafbinfo->fix.mmio_len = pci_resource_len(pdev, 1);
+       viafbinfo->fix.mmio_start = vdev->engine_start;
+       viafbinfo->fix.mmio_len = vdev->engine_len;
        viafbinfo->node = 0;
        viafbinfo->fbops = &viafb_ops;
        viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
@@ -1858,12 +1866,13 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
        viafbinfo->var = default_var;
 
        if (viafb_dual_fb) {
-               viafbinfo1 = framebuffer_alloc(viafb_par_length, &pdev->dev);
+               viafbinfo1 = framebuffer_alloc(viafb_par_length,
+                               &vdev->pdev->dev);
                if (!viafbinfo1) {
                        printk(KERN_ERR
                        "allocate the second framebuffer struct error\n");
-                       framebuffer_release(viafbinfo);
-                       return -ENOMEM;
+                       rc = -ENOMEM;
+                       goto out_fb_release;
                }
                viaparinfo1 = viafbinfo1->par;
                memcpy(viaparinfo1, viaparinfo, viafb_par_length);
@@ -1914,48 +1923,66 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
        viaparinfo->depth = fb_get_color_depth(&viafbinfo->var,
                &viafbinfo->fix);
        default_var.activate = FB_ACTIVATE_NOW;
-       fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
+       rc = fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
+       if (rc)
+               goto out_fb1_release;
 
        if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
            && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) {
-               if (register_framebuffer(viafbinfo1) < 0)
-                       return -EINVAL;
+               rc = register_framebuffer(viafbinfo1);
+               if (rc)
+                       goto out_dealloc_cmap;
        }
-       if (register_framebuffer(viafbinfo) < 0)
-               return -EINVAL;
+       rc = register_framebuffer(viafbinfo);
+       if (rc)
+               goto out_fb1_unreg_lcd_cle266;
 
        if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device)
                        || (viaparinfo->chip_info->gfx_chip_name !=
                        UNICHROME_CLE266))) {
-               if (register_framebuffer(viafbinfo1) < 0)
-                       return -EINVAL;
+               rc = register_framebuffer(viafbinfo1);
+               if (rc)
+                       goto out_fb_unreg;
        }
        DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n",
                  viafbinfo->node, viafbinfo->fix.id, default_var.xres,
                  default_var.yres, default_var.bits_per_pixel);
 
+#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
        viafb_init_proc(&viaparinfo->shared->proc_entry);
+#endif
        viafb_init_dac(IGA2);
        return 0;
+
+out_fb_unreg:
+       unregister_framebuffer(viafbinfo);
+out_fb1_unreg_lcd_cle266:
+       if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
+           && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266))
+               unregister_framebuffer(viafbinfo1);
+out_dealloc_cmap:
+       fb_dealloc_cmap(&viafbinfo->cmap);
+out_fb1_release:
+       if (viafbinfo1)
+               framebuffer_release(viafbinfo1);
+out_fb_release:
+       framebuffer_release(viafbinfo);
+       return rc;
 }
 
-static void __devexit via_pci_remove(struct pci_dev *pdev)
+void __devexit via_fb_pci_remove(struct pci_dev *pdev)
 {
        DEBUG_MSG(KERN_INFO "via_pci_remove!\n");
        fb_dealloc_cmap(&viafbinfo->cmap);
        unregister_framebuffer(viafbinfo);
        if (viafb_dual_fb)
                unregister_framebuffer(viafbinfo1);
-       iounmap((void *)viafbinfo->screen_base);
-       iounmap(viaparinfo->shared->engine_mmio);
-
-       viafb_delete_i2c_buss(viaparinfo);
-
+#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
+       viafb_remove_proc(viaparinfo->shared->proc_entry);
+#endif
        framebuffer_release(viafbinfo);
        if (viafb_dual_fb)
                framebuffer_release(viafbinfo1);
-
-       viafb_remove_proc(viaparinfo->shared->proc_entry);
 }
 
 #ifndef MODULE
@@ -2031,41 +2058,10 @@ static int __init viafb_setup(char *options)
 }
 #endif
 
-static struct pci_device_id viafb_pci_table[] __devinitdata = {
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
-         .driver_data = UNICHROME_CLE266 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
-         .driver_data = UNICHROME_PM800 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
-         .driver_data = UNICHROME_K400 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID),
-         .driver_data = UNICHROME_K800 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
-         .driver_data = UNICHROME_CN700 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
-         .driver_data = UNICHROME_K8M890 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID),
-         .driver_data = UNICHROME_CX700 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
-         .driver_data = UNICHROME_P4M900 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID),
-         .driver_data = UNICHROME_CN750 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID),
-         .driver_data = UNICHROME_VX800 },
-       { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),
-         .driver_data = UNICHROME_VX855 },
-       { }
-};
-MODULE_DEVICE_TABLE(pci, viafb_pci_table);
-
-static struct pci_driver viafb_driver = {
-       .name           = "viafb",
-       .id_table       = viafb_pci_table,
-       .probe          = via_pci_probe,
-       .remove         = __devexit_p(via_pci_remove),
-};
-
-static int __init viafb_init(void)
+/*
+ * These are called out of via-core for now.
+ */
+int __init viafb_init(void)
 {
        u32 dummy;
 #ifndef MODULE
@@ -2084,13 +2080,12 @@ static int __init viafb_init(void)
        printk(KERN_INFO
        "VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n",
               VERSION_MAJOR, VERSION_MINOR);
-       return pci_register_driver(&viafb_driver);
+       return 0;
 }
 
-static void __exit viafb_exit(void)
+void __exit viafb_exit(void)
 {
        DEBUG_MSG(KERN_INFO "viafb_exit!\n");
-       pci_unregister_driver(&viafb_driver);
 }
 
 static struct fb_ops viafb_ops = {
@@ -2110,8 +2105,6 @@ static struct fb_ops viafb_ops = {
        .fb_sync = viafb_sync,
 };
 
-module_init(viafb_init);
-module_exit(viafb_exit);
 
 #ifdef MODULE
 module_param(viafb_mode, charp, S_IRUSR);
index 61b5953..52a35fa 100644 (file)
 
 #include <linux/proc_fs.h>
 #include <linux/fb.h>
+#include <linux/spinlock.h>
 
 #include "ioctl.h"
 #include "share.h"
 #include "chip.h"
 #include "hw.h"
-#include "via_i2c.h"
 
 #define VERSION_MAJOR       2
 #define VERSION_KERNEL      6  /* For kernel 2.6 */
 #define VERSION_OS          0  /* 0: for 32 bits OS, 1: for 64 bits OS */
 #define VERSION_MINOR       4
 
+#define VIAFB_NUM_I2C          5
+
 struct viafb_shared {
        struct proc_dir_entry *proc_entry;      /*viafb proc entry */
-
-       /* I2C stuff */
-       struct via_i2c_stuff i2c_stuff;
+       struct viafb_dev *vdev;                 /* Global dev info */
 
        /* All the information will be needed to set engine */
        struct tmds_setting_information tmds_setting_info;
@@ -51,7 +51,6 @@ struct viafb_shared {
        struct chip_information chip_info;
 
        /* hardware acceleration stuff */
-       void __iomem *engine_mmio;
        u32 cursor_vram_addr;
        u32 vq_vram_addr;       /* virtual queue address in video ram */
        int (*hw_bitblt)(void __iomem *engine, u8 op, u32 width, u32 height,
@@ -99,4 +98,9 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
 void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
                              *plvds_setting_info, struct lvds_chip_information
                              *plvds_chip_info, struct IODATA io_data);
+int via_fb_pci_probe(struct viafb_dev *vdev);
+void via_fb_pci_remove(struct pci_dev *pdev);
+/* Temporary */
+int viafb_init(void);
+void viafb_exit(void);
 #endif /* __VIAFBDEV_H__ */
index af50e24..2dbad3c 100644 (file)
@@ -19,6 +19,7 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/via-core.h>
 #include "global.h"
 struct res_map_refresh res_map_refresh_tbl[] = {
 /*hres, vres, vclock, vmode_refresh*/
@@ -66,6 +67,7 @@ struct res_map_refresh res_map_refresh_tbl[] = {
        {1088, 612, RES_1088X612_60HZ_PIXCLOCK, 60},
        {1152, 720, RES_1152X720_60HZ_PIXCLOCK, 60},
        {1200, 720, RES_1200X720_60HZ_PIXCLOCK, 60},
+       {1200, 900, RES_1200X900_60HZ_PIXCLOCK, 60},
        {1280, 600, RES_1280X600_60HZ_PIXCLOCK, 60},
        {1280, 720, RES_1280X720_50HZ_PIXCLOCK, 50},
        {1280, 768, RES_1280X768_50HZ_PIXCLOCK, 50},
@@ -759,6 +761,16 @@ struct crt_mode_table CRTM1200x720[] = {
         {1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} }
 };
 
+/* 1200x900 (DCON) */
+struct crt_mode_table DCON1200x900[] = {
+       /* r_rate,          vclk,               hsp,               vsp   */
+       {REFRESH_60, CLK_57_275M, M1200X900_R60_HSP, M1200X900_R60_VSP,
+       /* The correct htotal is 1240, but this doesn't raster on VX855. */
+       /* Via suggested changing to a multiple of 16, hence 1264.       */
+       /*  HT,   HA,  HBS, HBE,  HSS, HSE,  VT,  VA, VBS, VBE, VSS, VSE */
+        {1264, 1200, 1200,  64, 1211,  32, 912, 900, 900,  12, 901, 10} }
+};
+
 /* 1280x600 (GTF) */
 struct crt_mode_table CRTM1280x600[] = {
        /* r_rate,          vclk,              hsp,             vsp   */
@@ -937,6 +949,9 @@ struct VideoModeTable viafb_modes[] = {
        /* Display : 1200x720 (GTF) */
        {CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
 
+       /* Display : 1200x900 (DCON) */
+       {DCON1200x900, ARRAY_SIZE(DCON1200x900)},
+
        /* Display : 1280x600 (GTF) */
        {CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
 
index a6b3749..d65bf1a 100644 (file)
@@ -19,6 +19,8 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
 #include "global.h"
 
 u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
@@ -27,9 +29,8 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
 {
        u8 data;
 
-       viaparinfo->shared->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
-       viafb_i2c_readbyte(plvds_chip_info->lvds_chip_slave_addr, index, &data);
-
+       viafb_i2c_readbyte(plvds_chip_info->i2c_port,
+                          plvds_chip_info->lvds_chip_slave_addr, index, &data);
        return data;
 }
 
@@ -39,14 +40,13 @@ void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
 {
        int index, data;
 
-       viaparinfo->shared->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
-
        index = io_data.Index;
        data = viafb_gpio_i2c_read_lvds(plvds_setting_info, plvds_chip_info,
                index);
        data = (data & (~io_data.Mask)) | io_data.Data;
 
-       viafb_i2c_writebyte(plvds_chip_info->lvds_chip_slave_addr, index, data);
+       viafb_i2c_writebyte(plvds_chip_info->i2c_port,
+                           plvds_chip_info->lvds_chip_slave_addr, index, data);
 }
 
 void viafb_init_lvds_vt1636(struct lvds_setting_information
@@ -159,7 +159,7 @@ void viafb_disable_lvds_vt1636(struct lvds_setting_information
        }
 }
 
-bool viafb_lvds_identify_vt1636(void)
+bool viafb_lvds_identify_vt1636(u8 i2c_adapter)
 {
        u8 Buffer[2];
 
@@ -167,26 +167,20 @@ bool viafb_lvds_identify_vt1636(void)
 
        /* Sense VT1636 LVDS Transmiter */
        viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
-       VT1636_LVDS_I2C_ADDR;
+               VT1636_LVDS_I2C_ADDR;
 
        /* Check vendor ID first: */
-       viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
-       lvds_chip_slave_addr,
-                   0x00, &Buffer[0]);
-       viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
-               lvds_chip_slave_addr,
-                   0x01, &Buffer[1]);
+       if (viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR,
+                                       0x00, &Buffer[0]))
+               return false;
+       viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x01, &Buffer[1]);
 
        if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11)))
                return false;
 
        /* Check Chip ID: */
-       viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
-       lvds_chip_slave_addr,
-                   0x02, &Buffer[0]);
-       viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
-               lvds_chip_slave_addr,
-                   0x03, &Buffer[1]);
+       viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x02, &Buffer[0]);
+       viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x03, &Buffer[1]);
        if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) {
                viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
                        VT1636_LVDS;
index 2a150c5..4c1314e 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef _VT1636_H_
 #define _VT1636_H_
 #include "chip.h"
-bool viafb_lvds_identify_vt1636(void);
+bool viafb_lvds_identify_vt1636(u8 i2c_adapter);
 void viafb_init_lvds_vt1636(struct lvds_setting_information
        *plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
 void viafb_enable_lvds_vt1636(struct lvds_setting_information
diff --git a/include/linux/via-core.h b/include/linux/via-core.h
new file mode 100644 (file)
index 0000000..7ffb521
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Jonathan Corbet <corbet@lwn.net>
+ * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation;
+ * either version 2, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE.See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __VIA_CORE_H__
+#define __VIA_CORE_H__
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+/*
+ * A description of each known serial I2C/GPIO port.
+ */
+enum via_port_type {
+       VIA_PORT_NONE = 0,
+       VIA_PORT_I2C,
+       VIA_PORT_GPIO,
+};
+
+enum via_port_mode {
+       VIA_MODE_OFF = 0,
+       VIA_MODE_I2C,           /* Used as I2C port */
+       VIA_MODE_GPIO,  /* Two GPIO ports */
+};
+
+enum viafb_i2c_adap {
+       VIA_PORT_26 = 0,
+       VIA_PORT_31,
+       VIA_PORT_25,
+       VIA_PORT_2C,
+       VIA_PORT_3D,
+};
+#define VIAFB_NUM_PORTS 5
+
+struct via_port_cfg {
+       enum via_port_type      type;
+       enum via_port_mode      mode;
+       u16                     io_port;
+       u8                      ioport_index;
+};
+
+/*
+ * This is the global viafb "device" containing stuff needed by
+ * all subdevs.
+ */
+struct viafb_dev {
+       struct pci_dev *pdev;
+       int chip_type;
+       struct via_port_cfg *port_cfg;
+       /*
+        * Spinlock for access to device registers.  Not yet
+        * globally used.
+        */
+       spinlock_t reg_lock;
+       /*
+        * The framebuffer MMIO region.  Little, if anything, touches
+        * this memory directly, and certainly nothing outside of the
+        * framebuffer device itself.  We *do* have to be able to allocate
+        * chunks of this memory for other devices, though.
+        */
+       unsigned long fbmem_start;
+       long fbmem_len;
+       void __iomem *fbmem;
+#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
+       long camera_fbmem_offset;
+       long camera_fbmem_size;
+#endif
+       /*
+        * The MMIO region for device registers.
+        */
+       unsigned long engine_start;
+       unsigned long engine_len;
+       void __iomem *engine_mmio;
+
+};
+
+/*
+ * Interrupt management.
+ */
+
+void viafb_irq_enable(u32 mask);
+void viafb_irq_disable(u32 mask);
+
+/*
+ * The global interrupt control register and its bits.
+ */
+#define VDE_INTERRUPT  0x200   /* Video interrupt flags/masks */
+#define   VDE_I_DVISENSE  0x00000001  /* DVI sense int status */
+#define   VDE_I_VBLANK    0x00000002  /* Vertical blank status */
+#define   VDE_I_MCCFI    0x00000004  /* MCE compl. frame int status */
+#define   VDE_I_VSYNC    0x00000008  /* VGA VSYNC int status */
+#define   VDE_I_DMA0DDONE 0x00000010  /* DMA 0 descr done */
+#define   VDE_I_DMA0TDONE 0x00000020  /* DMA 0 transfer done */
+#define   VDE_I_DMA1DDONE 0x00000040  /* DMA 1 descr done */
+#define   VDE_I_DMA1TDONE 0x00000080  /* DMA 1 transfer done */
+#define   VDE_I_C1AV      0x00000100  /* Cap Eng 1 act vid end */
+#define   VDE_I_HQV0     0x00000200  /* First HQV engine */
+#define   VDE_I_HQV1      0x00000400  /* Second HQV engine */
+#define   VDE_I_HQV1EN   0x00000800  /* Second HQV engine enable */
+#define   VDE_I_C0AV      0x00001000  /* Cap Eng 0 act vid end */
+#define   VDE_I_C0VBI     0x00002000  /* Cap Eng 0 VBI end */
+#define   VDE_I_C1VBI     0x00004000  /* Cap Eng 1 VBI end */
+#define   VDE_I_VSYNC2    0x00008000  /* Sec. Disp. VSYNC */
+#define   VDE_I_DVISNSEN  0x00010000  /* DVI sense enable */
+#define   VDE_I_VSYNC2EN  0x00020000  /* Sec Disp VSYNC enable */
+#define   VDE_I_MCCFIEN          0x00040000  /* MC comp frame int mask enable */
+#define   VDE_I_VSYNCEN   0x00080000  /* VSYNC enable */
+#define   VDE_I_DMA0DDEN  0x00100000  /* DMA 0 descr done enable */
+#define   VDE_I_DMA0TDEN  0x00200000  /* DMA 0 trans done enable */
+#define   VDE_I_DMA1DDEN  0x00400000  /* DMA 1 descr done enable */
+#define   VDE_I_DMA1TDEN  0x00800000  /* DMA 1 trans done enable */
+#define   VDE_I_C1AVEN    0x01000000  /* cap 1 act vid end enable */
+#define   VDE_I_HQV0EN   0x02000000  /* First hqv engine enable */
+#define   VDE_I_C1VBIEN          0x04000000  /* Cap 1 VBI end enable */
+#define   VDE_I_LVDSSI    0x08000000  /* LVDS sense interrupt */
+#define   VDE_I_C0AVEN    0x10000000  /* Cap 0 act vid end enable */
+#define   VDE_I_C0VBIEN   0x20000000  /* Cap 0 VBI end enable */
+#define   VDE_I_LVDSSIEN  0x40000000  /* LVDS Sense enable */
+#define   VDE_I_ENABLE   0x80000000  /* Global interrupt enable */
+
+/*
+ * DMA management.
+ */
+int viafb_request_dma(void);
+void viafb_release_dma(void);
+/* void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len); */
+int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg);
+
+/*
+ * DMA Controller registers.
+ */
+#define VDMA_MR0       0xe00           /* Mod reg 0 */
+#define   VDMA_MR_CHAIN   0x01         /* Chaining mode */
+#define   VDMA_MR_TDIE    0x02         /* Transfer done int enable */
+#define VDMA_CSR0      0xe04           /* Control/status */
+#define          VDMA_C_ENABLE   0x01            /* DMA Enable */
+#define          VDMA_C_START    0x02            /* Start a transfer */
+#define          VDMA_C_ABORT    0x04            /* Abort a transfer */
+#define          VDMA_C_DONE     0x08            /* Transfer is done */
+#define VDMA_MARL0     0xe20           /* Mem addr low */
+#define VDMA_MARH0     0xe24           /* Mem addr high */
+#define VDMA_DAR0      0xe28           /* Device address */
+#define VDMA_DQWCR0    0xe2c           /* Count (16-byte) */
+#define VDMA_TMR0      0xe30           /* Tile mode reg */
+#define VDMA_DPRL0     0xe34           /* Not sure */
+#define          VDMA_DPR_IN     0x08          /* Inbound transfer to FB */
+#define VDMA_DPRH0     0xe38
+#define VDMA_PMR0      (0xe00 + 0x134) /* Pitch mode */
+
+/*
+ * Useful stuff that probably belongs somewhere global.
+ */
+#define VGA_WIDTH      640
+#define VGA_HEIGHT     480
+
+/*
+ * Indexed port operations.  Note that these are all multi-op
+ * functions; every invocation will be racy if you're not holding
+ * reg_lock.
+ */
+
+#define VIAStatus   0x3DA  /* Non-indexed port */
+#define VIACR       0x3D4
+#define VIASR       0x3C4
+#define VIAGR       0x3CE
+#define VIAAR       0x3C0
+
+static inline u8 via_read_reg(u16 port, u8 index)
+{
+       outb(index, port);
+       return inb(port + 1);
+}
+
+static inline void via_write_reg(u16 port, u8 index, u8 data)
+{
+       outb(index, port);
+       outb(data, port + 1);
+}
+
+static inline void via_write_reg_mask(u16 port, u8 index, u8 data, u8 mask)
+{
+       u8 old;
+
+       outb(index, port);
+       old = inb(port + 1);
+       outb((data & mask) | (old & ~mask), port + 1);
+}
+
+#define VIA_MISC_REG_READ      0x03CC
+#define VIA_MISC_REG_WRITE     0x03C2
+
+static inline void via_write_misc_reg_mask(u8 data, u8 mask)
+{
+       u8 old = inb(VIA_MISC_REG_READ);
+       outb((data & mask) | (old & ~mask), VIA_MISC_REG_WRITE);
+}
+
+
+#endif /* __VIA_CORE_H__ */
diff --git a/include/linux/via-gpio.h b/include/linux/via-gpio.h
new file mode 100644 (file)
index 0000000..8281aea
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Support for viafb GPIO ports.
+ *
+ * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
+ * Distributable under version 2 of the GNU General Public License.
+ */
+
+#ifndef __VIA_GPIO_H__
+#define __VIA_GPIO_H__
+
+extern int viafb_gpio_lookup(const char *name);
+extern int viafb_gpio_init(void);
+extern void viafb_gpio_exit(void);
+#endif
similarity index 65%
rename from drivers/video/via/via_i2c.h
rename to include/linux/via_i2c.h
index 3a13242..44532e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
  * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
 
  * This program is free software; you can redistribute it and/or
 
 struct via_i2c_stuff {
        u16 i2c_port;                   /* GPIO or I2C port */
+       u16 is_active;                  /* Being used as I2C? */
        struct i2c_adapter adapter;
        struct i2c_algo_bit_data algo;
 };
 
-#define I2CPORT           0x3c4
-#define I2CPORTINDEX      0x31
-#define GPIOPORT          0x3C4
-#define GPIOPORTINDEX     0x2C
-#define I2C_BUS             1
-#define GPIO_BUS            2
-#define DELAYPORT           0x3C3
-
-int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata);
-int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data);
-int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len);
-int viafb_create_i2c_bus(void *par);
-void viafb_delete_i2c_buss(void *par);
+
+int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata);
+int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data);
+int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len);
+struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which);
+
+extern int viafb_i2c_init(void);
+extern void viafb_i2c_exit(void);
 #endif /* __VIA_I2C_H__ */