summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig63
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/arkfb.c1200
-rw-r--r--drivers/video/atmel_lcdfb.c752
-rw-r--r--drivers/video/console/Kconfig7
-rw-r--r--drivers/video/console/softcursor.c2
-rw-r--r--drivers/video/fbmem.c4
-rw-r--r--drivers/video/i810/i810_main.c2
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c2
-rw-r--r--drivers/video/matrox/matroxfb_accel.c2
-rw-r--r--drivers/video/matrox/matroxfb_base.c2
-rw-r--r--drivers/video/matrox/matroxfb_misc.c2
-rw-r--r--drivers/video/nvidia/nv_hw.c7
-rw-r--r--drivers/video/nvidia/nvidia.c2
-rw-r--r--drivers/video/pm2fb.c38
-rw-r--r--drivers/video/pm3fb.c3983
-rw-r--r--drivers/video/riva/rivafb-i2c.c2
-rw-r--r--drivers/video/s3fb.c19
-rw-r--r--drivers/video/skeletonfb.c2
-rw-r--r--drivers/video/svgalib.c17
-rw-r--r--drivers/video/vt8623fb.c927
21 files changed, 3677 insertions, 3361 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 1132ba5ff391..eebcb708cff1 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -3,6 +3,7 @@
#
menu "Graphics support"
+ depends on HAS_IOMEM
source "drivers/video/backlight/Kconfig"
source "drivers/video/display/Kconfig"
@@ -747,6 +748,22 @@ config FB_S1D13XXX
working with S1D13806). Product specs at
<http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
+config FB_ATMEL
+ tristate "AT91/AT32 LCD Controller support"
+ depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This enables support for the AT91/AT32 LCD Controller.
+
+config FB_INTSRAM
+ bool "Frame Buffer in internal SRAM"
+ depends on FB_ATMEL && ARCH_AT91SAM9261
+ help
+ Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
+ to let frame buffer in external SDRAM.
+
config FB_NVIDIA
tristate "nVidia Framebuffer Support"
depends on FB && PCI
@@ -779,6 +796,15 @@ config FB_NVIDIA_I2C
independently validate video mode parameters, you should say Y
here.
+config FB_NVIDIA_DEBUG
+ bool "Lots of debug output"
+ depends on FB_NVIDIA
+ default n
+ help
+ Say Y here if you want the nVidia driver to output all sorts
+ of debugging information to provide to the maintainer when
+ something goes wrong.
+
config FB_NVIDIA_BACKLIGHT
bool "Support for backlight control"
depends on FB_NVIDIA
@@ -818,7 +844,7 @@ config FB_RIVA_I2C
here.
config FB_RIVA_DEBUG
- bool "Lots of debug output from Riva(nVidia) driver"
+ bool "Lots of debug output"
depends on FB_RIVA
default n
help
@@ -1348,6 +1374,20 @@ config FB_VOODOO1
Please read the <file:Documentation/fb/README-sstfb.txt> for supported
options and other important info support.
+config FB_VT8623
+ tristate "VIA VT8623 support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_TILEBLITTING
+ select FB_SVGALIB
+ select VGASTATE
+ select FONT_8x16 if FRAMEBUFFER_CONSOLE
+ ---help---
+ Driver for CastleRock integrated graphics core in the
+ VIA VT8623 [Apollo CLE266] chipset.
+
config FB_CYBLA
tristate "Cyberblade/i1 support"
depends on FB && PCI && X86_32 && !64BIT
@@ -1401,9 +1441,26 @@ config FB_TRIDENT_ACCEL
This will compile the Trident frame buffer device with
acceleration functions.
+config FB_ARK
+ tristate "ARK 2000PV support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_TILEBLITTING
+ select FB_SVGALIB
+ select VGASTATE
+ select FONT_8x16 if FRAMEBUFFER_CONSOLE
+ ---help---
+ Driver for PCI graphics boards with ARK 2000PV chip
+ and ICS 5342 RAMDAC.
+
config FB_PM3
- tristate "Permedia3 support"
- depends on FB && PCI && BROKEN
+ tristate "Permedia3 support (EXPERIMENTAL)"
+ depends on FB && PCI && EXPERIMENTAL
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
help
This is the frame buffer device driver for the 3DLabs Permedia3
chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 &
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a916c204274f..bd8b05229500 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -54,10 +54,12 @@ obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o
obj-$(CONFIG_FB_CT65550) += chipsfb.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o
+obj-$(CONFIG_FB_VT8623) += vt8623fb.o
obj-$(CONFIG_FB_CYBLA) += cyblafb.o
obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
obj-$(CONFIG_FB_LE80578) += vermilion/
obj-$(CONFIG_FB_S3) += s3fb.o
+obj-$(CONFIG_FB_ARK) += arkfb.o
obj-$(CONFIG_FB_STI) += stifb.o
obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o
@@ -85,6 +87,7 @@ obj-$(CONFIG_FB_G364) += g364fb.o
obj-$(CONFIG_FB_SA1100) += sa1100fb.o
obj-$(CONFIG_FB_HIT) += hitfb.o
obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
+obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o
obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c
new file mode 100644
index 000000000000..ba6fede5c466
--- /dev/null
+++ b/drivers/video/arkfb.c
@@ -0,0 +1,1200 @@
+/*
+ * linux/drivers/video/arkfb.c -- Frame buffer device driver for ARK 2000PV
+ * with ICS 5342 dac (it is easy to add support for different dacs).
+ *
+ * Copyright (c) 2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Code is based on s3fb
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct arkfb_info {
+ int mclk_freq;
+ int mtrr_reg;
+
+ struct dac_info *dac;
+ struct vgastate state;
+ struct mutex open_lock;
+ unsigned int ref_count;
+ u32 pseudo_palette[16];
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static const struct svga_fb_format arkfb_formats[] = {
+ { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1,
+ FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+ {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {24, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 8, 8},
+ {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2},
+ SVGA_FORMAT_END
+};
+
+
+/* CRT timing register sets */
+
+static const struct vga_regset ark_h_total_regs[] = {{0x00, 0, 7}, {0x41, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_h_display_regs[] = {{0x01, 0, 7}, {0x41, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_start_regs[] = {{0x02, 0, 7}, {0x41, 5, 5}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7 }, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_start_regs[] = {{0x04, 0, 7}, {0x41, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
+
+static const struct vga_regset ark_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x40, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x40, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x40, 5, 5}, VGA_REGSET_END};
+// const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x40, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
+
+static const struct vga_regset ark_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END};
+static const struct vga_regset ark_offset_regs[] = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END};
+
+static const struct svga_timing_regs ark_timing_regs = {
+ ark_h_total_regs, ark_h_display_regs, ark_h_blank_start_regs,
+ ark_h_blank_end_regs, ark_h_sync_start_regs, ark_h_sync_end_regs,
+ ark_v_total_regs, ark_v_display_regs, ark_v_blank_start_regs,
+ ark_v_blank_end_regs, ark_v_sync_start_regs, ark_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for ARK 2000PV");
+
+module_param(mode, charp, 0444);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+static int threshold = 4;
+
+module_param(threshold, int, 0644);
+MODULE_PARM_DESC(threshold, "FIFO threshold");
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map)
+{
+ const u8 *font = map->data;
+ u8 __iomem *fb = (u8 __iomem *)info->screen_base;
+ int i, c;
+
+ if ((map->width != 8) || (map->height != 16) ||
+ (map->depth != 1) || (map->length != 256)) {
+ printk(KERN_ERR "fb%d: unsupported font parameters: width %d, "
+ "height %d, depth %d, length %d\n", info->node,
+ map->width, map->height, map->depth, map->length);
+ return;
+ }
+
+ fb += 2;
+ for (c = 0; c < map->length; c++) {
+ for (i = 0; i < map->height; i++) {
+ fb_writeb(font[i], &fb[i * 4]);
+ fb_writeb(font[i], &fb[i * 4 + (128 * 8)]);
+ }
+ fb += 128;
+
+ if ((c % 8) == 7)
+ fb += 128*8;
+
+ font += map->height;
+ }
+}
+
+static struct fb_tile_ops arkfb_tile_ops = {
+ .fb_settile = arkfb_settile,
+ .fb_tilecopy = svga_tilecopy,
+ .fb_tilefill = svga_tilefill,
+ .fb_tileblit = svga_tileblit,
+ .fb_tilecursor = svga_tilecursor,
+ .fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+ return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* arkfb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = expand_color(image->fg_color);
+ u32 bg = expand_color(image->bg_color);
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = *(src++) * 0x01010101;
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+/* arkfb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ u32 fg = expand_color(rect->color);
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ int x, y;
+
+ dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+ + ((rect->dx / 8) * 4);
+
+ for (y = 0; y < rect->height; y++) {
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < rect->width; x += 8) {
+ fb_writel(fg, dst++);
+ }
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+ return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) |
+ ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF;
+}
+
+/* arkfb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = image->fg_color * 0x11111111;
+ u32 bg = image->bg_color * 0x11111111;
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = expand_pixel(*(src++));
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+static void arkfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+ && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+ if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+ arkfb_iplan_imageblit(info, image);
+ else
+ arkfb_cfb4_imageblit(info, image);
+ } else
+ cfb_imageblit(info, image);
+}
+
+static void arkfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ if ((info->var.bits_per_pixel == 4)
+ && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+ && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+ arkfb_iplan_fillrect(info, rect);
+ else
+ cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+enum
+{
+ DAC_PSEUDO8_8,
+ DAC_RGB1555_8,
+ DAC_RGB0565_8,
+ DAC_RGB0888_8,
+ DAC_RGB8888_8,
+ DAC_PSEUDO8_16,
+ DAC_RGB1555_16,
+ DAC_RGB0565_16,
+ DAC_RGB0888_16,
+ DAC_RGB8888_16,
+ DAC_MAX
+};
+
+struct dac_ops {
+ int (*dac_get_mode)(struct dac_info *info);
+ int (*dac_set_mode)(struct dac_info *info, int mode);
+ int (*dac_get_freq)(struct dac_info *info, int channel);
+ int (*dac_set_freq)(struct dac_info *info, int channel, u32 freq);
+ void (*dac_release)(struct dac_info *info);
+};
+
+typedef void (*dac_read_regs_t)(void *data, u8 *code, int count);
+typedef void (*dac_write_regs_t)(void *data, u8 *code, int count);
+
+struct dac_info
+{
+ struct dac_ops *dacops;
+ dac_read_regs_t dac_read_regs;
+ dac_write_regs_t dac_write_regs;
+ void *data;
+};
+
+
+static inline u8 dac_read_reg(struct dac_info *info, u8 reg)
+{
+ u8 code[2] = {reg, 0};
+ info->dac_read_regs(info->data, code, 1);
+ return code[1];
+}
+
+static inline void dac_read_regs(struct dac_info *info, u8 *code, int count)
+{
+ info->dac_read_regs(info->data, code, count);
+}
+
+static inline void dac_write_reg(struct dac_info *info, u8 reg, u8 val)
+{
+ u8 code[2] = {reg, val};
+ info->dac_write_regs(info->data, code, 1);
+}
+
+static inline void dac_write_regs(struct dac_info *info, u8 *code, int count)
+{
+ info->dac_write_regs(info->data, code, count);
+}
+
+static inline int dac_set_mode(struct dac_info *info, int mode)
+{
+ return info->dacops->dac_set_mode(info, mode);
+}
+
+static inline int dac_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+ return info->dacops->dac_set_freq(info, channel, freq);
+}
+
+static inline void dac_release(struct dac_info *info)
+{
+ info->dacops->dac_release(info);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* ICS5342 DAC */
+
+struct ics5342_info
+{
+ struct dac_info dac;
+ u8 mode;
+};
+
+#define DAC_PAR(info) ((struct ics5342_info *) info)
+
+/* LSB is set to distinguish unused slots */
+static const u8 ics5342_mode_table[DAC_MAX] = {
+ [DAC_PSEUDO8_8] = 0x01, [DAC_RGB1555_8] = 0x21, [DAC_RGB0565_8] = 0x61,
+ [DAC_RGB0888_8] = 0x41, [DAC_PSEUDO8_16] = 0x11, [DAC_RGB1555_16] = 0x31,
+ [DAC_RGB0565_16] = 0x51, [DAC_RGB0888_16] = 0x91, [DAC_RGB8888_16] = 0x71
+};
+
+static int ics5342_set_mode(struct dac_info *info, int mode)
+{
+ u8 code;
+
+ if (mode >= DAC_MAX)
+ return -EINVAL;
+
+ code = ics5342_mode_table[mode];
+
+ if (! code)
+ return -EINVAL;
+
+ dac_write_reg(info, 6, code & 0xF0);
+ DAC_PAR(info)->mode = mode;
+
+ return 0;
+}
+
+static const struct svga_pll ics5342_pll = {3, 129, 3, 33, 0, 3,
+ 60000, 250000, 14318};
+
+/* pd4 - allow only posdivider 4 (r=2) */
+static const struct svga_pll ics5342_pll_pd4 = {3, 129, 3, 33, 2, 2,
+ 60000, 335000, 14318};
+
+/* 270 MHz should be upper bound for VCO clock according to specs,
+ but that is too restrictive in pd4 case */
+
+static int ics5342_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+ u16 m, n, r;
+
+ /* only postdivider 4 (r=2) is valid in mode DAC_PSEUDO8_16 */
+ int rv = svga_compute_pll((DAC_PAR(info)->mode == DAC_PSEUDO8_16)
+ ? &ics5342_pll_pd4 : &ics5342_pll,
+ freq, &m, &n, &r, 0);
+
+ if (rv < 0) {
+ return -EINVAL;
+ } else {
+ u8 code[6] = {4, 3, 5, m-2, 5, (n-2) | (r << 5)};
+ dac_write_regs(info, code, 3);
+ return 0;
+ }
+}
+
+static void ics5342_release(struct dac_info *info)
+{
+ ics5342_set_mode(info, DAC_PSEUDO8_8);
+ kfree(info);
+}
+
+static struct dac_ops ics5342_ops = {
+ .dac_set_mode = ics5342_set_mode,
+ .dac_set_freq = ics5342_set_freq,
+ .dac_release = ics5342_release
+};
+
+
+static struct dac_info * ics5342_init(dac_read_regs_t drr, dac_write_regs_t dwr, void *data)
+{
+ struct dac_info *info = kzalloc(sizeof(struct ics5342_info), GFP_KERNEL);
+
+ if (! info)
+ return NULL;
+
+ info->dacops = &ics5342_ops;
+ info->dac_read_regs = drr;
+ info->dac_write_regs = dwr;
+ info->data = data;
+ DAC_PAR(info)->mode = DAC_PSEUDO8_8; /* estimation */
+ return info;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7};
+
+static void ark_dac_read_regs(void *data, u8 *code, int count)
+{
+ u8 regval = vga_rseq(NULL, 0x1C);
+
+ while (count != 0)
+ {
+ vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+ code[1] = vga_r(NULL, dac_regs[code[0] & 3]);
+ count--;
+ code += 2;
+ }
+
+ vga_wseq(NULL, 0x1C, regval);
+}
+
+static void ark_dac_write_regs(void *data, u8 *code, int count)
+{
+ u8 regval = vga_rseq(NULL, 0x1C);
+
+ while (count != 0)
+ {
+ vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+ vga_w(NULL, dac_regs[code[0] & 3], code[1]);
+ count--;
+ code += 2;
+ }
+
+ vga_wseq(NULL, 0x1C, regval);
+}
+
+
+static void ark_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+ struct arkfb_info *par = info->par;
+ u8 regval;
+
+ int rv = dac_set_freq(par->dac, 0, 1000000000 / pixclock);
+ if (rv < 0) {
+ printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+ return;
+ }
+
+ /* Set VGA misc register */
+ regval = vga_r(NULL, VGA_MIS_R);
+ vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+}
+
+
+/* Open framebuffer */
+
+static int arkfb_open(struct fb_info *info, int user)
+{
+ struct arkfb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ memset(&(par->state), 0, sizeof(struct vgastate));
+ par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+ par->state.num_crtc = 0x60;
+ par->state.num_seq = 0x30;
+ save_vga(&(par->state));
+ }
+
+ par->ref_count++;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+/* Close framebuffer */
+
+static int arkfb_release(struct fb_info *info, int user)
+{
+ struct arkfb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ return -EINVAL;
+ }
+
+ if (par->ref_count == 1) {
+ restore_vga(&(par->state));
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ }
+
+ par->ref_count--;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+/* Validate passed in var */
+
+static int arkfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int rv, mem, step;
+
+ /* Find appropriate format */
+ rv = svga_match_format (arkfb_formats, var, NULL);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+ return rv;
+ }
+
+ /* Do not allow to have real resoulution larger than virtual */
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ /* Round up xres_virtual to have proper alignment of lines */
+ step = arkfb_formats[rv].xresstep - 1;
+ var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+
+ /* Check whether have enough memory */
+ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+ if (mem > info->screen_size)
+ {
+ printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+ return -EINVAL;
+ }
+
+ rv = svga_check_timings (&ark_timing_regs, var, info->node);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+ return rv;
+ }
+
+ /* Interlaced mode is broken */
+ if (var->vmode & FB_VMODE_INTERLACED)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Set video mode from par */
+
+static int arkfb_set_par(struct fb_info *info)
+{
+ struct arkfb_info *par = info->par;
+ u32 value, mode, hmul, hdiv, offset_value, screen_size;
+ u32 bpp = info->var.bits_per_pixel;
+ u8 regval;
+
+ if (bpp != 0) {
+ info->fix.ypanstep = 1;
+ info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+ info->flags &= ~FBINFO_MISC_TILEBLITTING;
+ info->tileops = NULL;
+
+ /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+ info->pixmap.blit_y = ~(u32)0;
+
+ offset_value = (info->var.xres_virtual * bpp) / 64;
+ screen_size = info->var.yres_virtual * info->fix.line_length;
+ } else {
+ info->fix.ypanstep = 16;
+ info->fix.line_length = 0;
+
+ info->flags |= FBINFO_MISC_TILEBLITTING;
+ info->tileops = &arkfb_tile_ops;
+
+ /* supports 8x16 tiles only */
+ info->pixmap.blit_x = 1 << (8 - 1);
+ info->pixmap.blit_y = 1 << (16 - 1);
+
+ offset_value = info->var.xres_virtual / 16;
+ screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+ }
+
+ info->var.xoffset = 0;
+ info->var.yoffset = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+
+ /* Unlock registers */
+ svga_wcrt_mask(0x11, 0x00, 0x80);
+
+ /* Blank screen and turn off sync */
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+
+ /* Set default values */
+ svga_set_default_gfx_regs();
+ svga_set_default_atc_regs();
+ svga_set_default_seq_regs();
+ svga_set_default_crt_regs();
+ svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF);
+ svga_wcrt_multi(ark_start_address_regs, 0);
+
+ /* ARK specific initialization */
+ svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */
+ svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */
+
+ vga_wseq(NULL, 0x13, info->fix.smem_start >> 16);
+ vga_wseq(NULL, 0x14, info->fix.smem_start >> 24);
+ vga_wseq(NULL, 0x15, 0);
+ vga_wseq(NULL, 0x16, 0);
+
+ /* Set the FIFO threshold register */
+ /* It is fascinating way to store 5-bit value in 8-bit register */
+ regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1;
+ vga_wseq(NULL, 0x18, regval);
+
+ /* Set the offset register */
+ pr_debug("fb%d: offset register : %d\n", info->node, offset_value);
+ svga_wcrt_multi(ark_offset_regs, offset_value);
+
+ /* fix for hi-res textmode */
+ svga_wcrt_mask(0x40, 0x08, 0x08);
+
+ if (info->var.vmode & FB_VMODE_DOUBLE)
+ svga_wcrt_mask(0x09, 0x80, 0x80);
+ else
+ svga_wcrt_mask(0x09, 0x00, 0x80);
+
+ if (info->var.vmode & FB_VMODE_INTERLACED)
+ svga_wcrt_mask(0x44, 0x04, 0x04);
+ else
+ svga_wcrt_mask(0x44, 0x00, 0x04);
+
+ hmul = 1;
+ hdiv = 1;
+ mode = svga_match_format(arkfb_formats, &(info->var), &(info->fix));
+
+ /* Set mode-specific register values */
+ switch (mode) {
+ case 0:
+ pr_debug("fb%d: text mode\n", info->node);
+ svga_set_textmode_vga_regs();
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+
+ break;
+ case 1:
+ pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ break;
+ case 2:
+ pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ break;
+ case 3:
+ pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */
+
+ if (info->var.pixclock > 20000) {
+ pr_debug("fb%d: not using multiplex\n", info->node);
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ } else {
+ pr_debug("fb%d: using multiplex\n", info->node);
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_16);
+ hdiv = 2;
+ }
+ break;
+ case 4:
+ pr_debug("fb%d: 5/5/5 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB1555_16);
+ break;
+ case 5:
+ pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB0565_16);
+ break;
+ case 6:
+ pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB0888_16);
+ hmul = 3;
+ hdiv = 2;
+ break;
+ case 7:
+ pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB8888_16);
+ hmul = 2;
+ break;
+ default:
+ printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node);
+ return -EINVAL;
+ }
+
+ ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul);
+ svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv,
+ (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1,
+ (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
+ hmul, info->node);
+
+ /* Set interlaced mode start/end register */
+ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
+ value = ((value * hmul / hdiv) / 8) - 5;
+ vga_wcrt(NULL, 0x42, (value + 1) / 2);
+
+ memset_io(info->screen_base, 0x00, screen_size);
+ /* Device and screen back on */
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+
+ return 0;
+}
+
+/* Set a colour register */
+
+static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ switch (fb->var.bits_per_pixel) {
+ case 0:
+ case 4:
+ if (regno >= 16)
+ return -EINVAL;
+
+ if ((fb->var.bits_per_pixel == 4) &&
+ (fb->var.nonstd == 0)) {
+ outb(0xF0, VGA_PEL_MSK);
+ outb(regno*16, VGA_PEL_IW);
+ } else {
+ outb(0x0F, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ }
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 8:
+ if (regno >= 256)
+ return -EINVAL;
+
+ outb(0xFF, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 16:
+ if (regno >= 16)
+ return 0;
+
+ if (fb->var.green.length == 5)
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+ ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+ else if (fb->var.green.length == 6)
+ ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ else
+ return -EINVAL;
+ break;
+ case 24:
+ case 32:
+ if (regno >= 16)
+ return 0;
+
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+ (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Set the display blanking state */
+
+static int arkfb_blank(int blank_mode, struct fb_info *info)
+{
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ pr_debug("fb%d: unblank\n", info->node);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ break;
+ case FB_BLANK_NORMAL:
+ pr_debug("fb%d: blank\n", info->node);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ break;
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_VSYNC_SUSPEND:
+ pr_debug("fb%d: sync down\n", info->node);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+ break;
+ }
+ return 0;
+}
+
+
+/* Pan the display */
+
+static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ unsigned int offset;
+
+ /* Calculate the offset */
+ if (var->bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+ offset = offset >> 2;
+ } else {
+ offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * var->bits_per_pixel / 8);
+ offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3);
+ }
+
+ /* Set the offset */
+ svga_wcrt_multi(ark_start_address_regs, offset);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops arkfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = arkfb_open,
+ .fb_release = arkfb_release,
+ .fb_check_var = arkfb_check_var,
+ .fb_set_par = arkfb_set_par,
+ .fb_setcolreg = arkfb_setcolreg,
+ .fb_blank = arkfb_blank,
+ .fb_pan_display = arkfb_pan_display,
+ .fb_fillrect = arkfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = arkfb_imageblit,
+ .fb_get_caps = svga_get_caps,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* PCI probe */
+static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct fb_info *info;
+ struct arkfb_info *par;
+ int rc;
+ u8 regval;
+
+ /* Ignore secondary VGA device because there is no VGA arbitration */
+ if (! svga_primary_device(dev)) {
+ dev_info(&(dev->dev), "ignoring secondary device\n");
+ return -ENODEV;
+ }
+
+ /* Allocate and fill driver data structure */
+ info = framebuffer_alloc(sizeof(struct arkfb_info), NULL);
+ if (! info) {
+ dev_err(&(dev->dev), "cannot allocate memory\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ mutex_init(&par->open_lock);
+
+ info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+ info->fbops = &arkfb_ops;
+
+ /* Prepare PCI device */
+ rc = pci_enable_device(dev);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot enable PCI device\n");
+ goto err_enable_device;
+ }
+
+ rc = pci_request_regions(dev, "arkfb");
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ goto err_request_regions;
+ }
+
+ par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info);
+ if (! par->dac) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "RAMDAC initialization failed\n");
+ goto err_dac;
+ }
+
+ info->fix.smem_start = pci_resource_start(dev, 0);
+ info->fix.smem_len = pci_resource_len(dev, 0);
+
+ /* Map physical IO memory address into kernel space */
+ info->screen_base = pci_iomap(dev, 0, 0);
+ if (! info->screen_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ goto err_iomap;
+ }
+
+ /* FIXME get memsize */
+ regval = vga_rseq(NULL, 0x10);
+ info->screen_size = (1 << (regval >> 6)) << 20;
+ info->fix.smem_len = info->screen_size;
+
+ strcpy(info->fix.id, "ARK 2000PV");
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->pseudo_palette = (void*) (par->pseudo_palette);
+
+ /* Prepare startup mode */
+ rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ if (! ((rc == 1) || (rc == 2))) {
+ rc = -EINVAL;
+ dev_err(&(dev->dev), "mode %s not found\n", mode);
+ goto err_find_mode;
+ }
+
+ rc = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot allocate colormap\n");
+ goto err_alloc_cmap;
+ }
+
+ rc = register_framebuffer(info);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot register framebugger\n");
+ goto err_reg_fb;
+ }
+
+ printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+ pci_name(dev), info->fix.smem_len >> 20);
+
+ /* Record a reference to the driver data */
+ pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+ if (mtrr) {
+ par->mtrr_reg = -1;
+ par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+
+ return 0;
+
+ /* Error handling */
+err_reg_fb:
+ fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+ pci_iounmap(dev, info->screen_base);
+err_iomap:
+ dac_release(par->dac);
+err_dac:
+ pci_release_regions(dev);
+err_request_regions:
+/* pci_disable_device(dev); */
+err_enable_device:
+ framebuffer_release(info);
+ return rc;
+}
+
+/* PCI remove */
+
+static void __devexit ark_pci_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ if (info) {
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+#endif
+
+ dac_release(par->dac);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ pci_iounmap(dev, info->screen_base);
+ pci_release_regions(dev);
+/* pci_disable_device(dev); */
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+ }
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ dev_info(&(dev->dev), "suspend\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ fb_set_suspend(info, 1);
+
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+
+ return 0;
+}
+
+
+/* PCI resume */
+
+static int ark_pci_resume (struct pci_dev* dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ dev_info(&(dev->dev), "resume\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+
+ if (pci_enable_device(dev))
+ goto fail;
+
+ pci_set_master(dev);
+
+ arkfb_set_par(info);
+ fb_set_suspend(info, 0);
+
+ mutex_unlock(&(par->open_lock));
+fail:
+ release_console_sem();
+ return 0;
+}
+#else
+#define ark_pci_suspend NULL
+#define ark_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id ark_devices[] __devinitdata = {
+ {PCI_DEVICE(0xEDD8, 0xA099)},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+
+MODULE_DEVICE_TABLE(pci, ark_devices);
+
+static struct pci_driver arkfb_pci_driver = {
+ .name = "arkfb",
+ .id_table = ark_devices,
+ .probe = ark_pci_probe,
+ .remove = __devexit_p(ark_pci_remove),
+ .suspend = ark_pci_suspend,
+ .resume = ark_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit arkfb_cleanup(void)
+{
+ pr_debug("arkfb: cleaning up\n");
+ pci_unregister_driver(&arkfb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+static int __init arkfb_init(void)
+{
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("arkfb", &option))
+ return -ENODEV;
+
+ if (option && *option)
+ mode = option;
+#endif
+
+ pr_debug("arkfb: initializing\n");
+ return pci_register_driver(&arkfb_pci_driver);
+}
+
+module_init(arkfb_init);
+module_exit(arkfb_cleanup);
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
new file mode 100644
index 000000000000..e1d5bd0c98c4
--- /dev/null
+++ b/drivers/video/atmel_lcdfb.c
@@ -0,0 +1,752 @@
+/*
+ * Driver for AT91/AT32 LCD Controller
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+
+#include <video/atmel_lcdc.h>
+
+#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
+#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+
+/* configurable parameters */
+#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+#define ATMEL_LCDC_DMA_BURST_LEN 8
+
+#if defined(CONFIG_ARCH_AT91SAM9263)
+#define ATMEL_LCDC_FIFO_SIZE 2048
+#else
+#define ATMEL_LCDC_FIFO_SIZE 512
+#endif
+
+#if defined(CONFIG_ARCH_AT91)
+#define ATMEL_LCDFB_FBINFO_DEFAULT FBINFO_DEFAULT
+
+static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+ struct fb_var_screeninfo *var)
+{
+
+}
+#elif defined(CONFIG_AVR32)
+#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+ | FBINFO_PARTIAL_PAN_OK \
+ | FBINFO_HWACCEL_XPAN \
+ | FBINFO_HWACCEL_YPAN)
+
+static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+ struct fb_var_screeninfo *var)
+{
+ u32 dma2dcfg;
+ u32 pixeloff;
+
+ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+
+ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+
+ /* Update configuration */
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+ lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+ | ATMEL_LCDC_DMAUPDT);
+}
+#endif
+
+
+static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+
+static void atmel_lcdfb_update_dma(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+{
+ struct atmel_lcdfb_info *sinfo = info->par;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ unsigned long dma_addr;
+
+ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+ + var->xoffset * var->bits_per_pixel / 8);
+
+ dma_addr &= ~3UL;
+
+ /* Set framebuffer DMA base address and pixel offset */
+ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+
+ atmel_lcdfb_update_dma2d(sinfo, var);
+}
+
+static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+ struct fb_info *info = sinfo->info;
+
+ dma_free_writecombine(info->device, info->fix.smem_len,
+ info->screen_base, info->fix.smem_start);
+}
+
+/**
+ * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+ * @sinfo: the frame buffer to allocate memory for
+ */
+static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+ struct fb_info *info = sinfo->info;
+ struct fb_var_screeninfo *var = &info->var;
+
+ info->fix.smem_len = (var->xres_virtual * var->yres_virtual
+ * ((var->bits_per_pixel + 7) / 8));
+
+ info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
+ (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+
+ if (!info->screen_base) {
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * atmel_lcdfb_check_var - Validates a var passed in.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
+ *
+ * Checks to see if the hardware supports the state requested by
+ * var passed in. This function does not alter the hardware
+ * state!!! This means the data stored in struct fb_info and
+ * struct atmel_lcdfb_info do not change. This includes the var
+ * inside of struct fb_info. Do NOT change these. This function
+ * can be called on its own if we intent to only test a mode and
+ * not actually set it. The stuff in modedb.c is a example of
+ * this. If the var passed in is slightly off by what the
+ * hardware can support then we alter the var PASSED in to what
+ * we can do. If the hardware doesn't support mode change a
+ * -EINVAL will be returned by the upper layers. You don't need
+ * to implement this function then. If you hardware doesn't
+ * support changing the resolution then this function is not
+ * needed. In this case the driver would just provide a var that
+ * represents the static state the screen is in.
+ *
+ * Returns negative errno on error, or zero on success.
+ */
+static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct device *dev = info->device;
+ struct atmel_lcdfb_info *sinfo = info->par;
+ unsigned long clk_value_khz;
+
+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+ dev_dbg(dev, "%s:\n", __func__);
+ dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
+ dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
+ dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
+ dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
+
+ if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+ dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+ return -EINVAL;
+ }
+
+ /* Force same alignment for each line */
+ var->xres = (var->xres + 3) & ~3UL;
+ var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+
+ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+ var->transp.offset = var->transp.length = 0;
+ var->xoffset = var->yoffset = 0;
+
+ switch (var->bits_per_pixel) {
+ case 2:
+ case 4:
+ case 8:
+ var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length
+ = var->bits_per_pixel;
+ break;
+ case 15:
+ case 16:
+ var->red.offset = 0;
+ var->green.offset = 5;
+ var->blue.offset = 10;
+ var->red.length = var->green.length = var->blue.length = 5;
+ break;
+ case 24:
+ case 32:
+ var->red.offset = 0;
+ var->green.offset = 8;
+ var->blue.offset = 16;
+ var->red.length = var->green.length = var->blue.length = 8;
+ break;
+ default:
+ dev_err(dev, "color depth %d not supported\n",
+ var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * atmel_lcdfb_set_par - Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
+ *
+ * Using the fb_var_screeninfo in fb_info we set the resolution
+ * of the this particular framebuffer. This function alters the
+ * par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+ * not alter var in fb_info since we are using that data. This
+ * means we depend on the data in var inside fb_info to be
+ * supported by the hardware. atmel_lcdfb_check_var is always called
+ * before atmel_lcdfb_set_par to ensure this. Again if you can't
+ * change the resolution you don't need this function.
+ *
+ */
+static int atmel_lcdfb_set_par(struct fb_info *info)
+{
+ struct atmel_lcdfb_info *sinfo = info->par;
+ unsigned long value;
+ unsigned long clk_value_khz;
+
+ dev_dbg(info->device, "%s:\n", __func__);
+ dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
+ info->var.xres, info->var.yres,
+ info->var.xres_virtual, info->var.yres_virtual);
+
+ /* Turn off the LCD controller and the DMA controller */
+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+
+ if (info->var.bits_per_pixel <= 8)
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ else
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+ info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+
+ /* Re-initialize the DMA engine... */
+ dev_dbg(info->device, " * update DMA engine\n");
+ atmel_lcdfb_update_dma(info, &info->var);
+
+ /* ...set frame size and burst length = 8 words (?) */
+ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+
+ /* Now, the LCDC core... */
+
+ /* Set pixel clock */
+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+ value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
+
+ if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
+ value++;
+
+ value = (value / 2) - 1;
+
+ if (value <= 0) {
+ dev_notice(info->device, "Bypassing pixel clock divider\n");
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+ } else
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+
+ /* Initialize control register 2 */
+ value = sinfo->default_lcdcon2;
+
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+ value |= ATMEL_LCDC_INVLINE_INVERTED;
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ value |= ATMEL_LCDC_INVFRAME_INVERTED;
+
+ switch (info->var.bits_per_pixel) {
+ case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
+ case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+ case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+ case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+ case 15: /* fall through */
+ case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+ case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+ case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+ default: BUG(); break;
+ }
+ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+
+ /* Vertical timing */
+ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+ value |= info->var.lower_margin;
+ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
+ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+
+ /* Horizontal timing */
+ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+ value |= (info->var.left_margin - 1);
+ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
+ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+
+ /* Display size */
+ value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+ value |= info->var.yres - 1;
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+
+ /* FIFO Threshold: Use formula from data sheet */
+ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+
+ /* Toggle LCD_MODE every frame */
+ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+
+ /* Disable all interrupts */
+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+ /* Set contrast */
+ value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+ /* ...wait for DMA engine to become idle... */
+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+ msleep(10);
+
+ dev_dbg(info->device, " * re-enable DMA engine\n");
+ /* ...and enable it with updated configuration */
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+
+ dev_dbg(info->device, " * re-enable LCDC core\n");
+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+
+ dev_dbg(info->device, " * DONE\n");
+
+ return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+/**
+ * atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+ * @regno: Which register in the CLUT we are programming
+ * @red: The red value which can be up to 16 bits wide
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
+ *
+ * Set a single color register. The values supplied have a 16 bit
+ * magnitude which needs to be scaled in this function for the hardware.
+ * Things to take into consideration are how many color registers, if
+ * any, are supported with the current color visual. With truecolor mode
+ * no color palettes are supported. Here a psuedo palette is created
+ * which we store the value in pseudo_palette in struct fb_info. For
+ * pseudocolor mode we have a limited color palette. To deal with this
+ * we can program what color is displayed for a particular pixel value.
+ * DirectColor is similar in that we can program each color field. If
+ * we have a static colormap we don't need to implement this function.
+ *
+ * Returns negative errno on error, or zero on success. In an
+ * ideal world, this would have been the case, but as it turns
+ * out, the other drivers return 1 on failure, so that's what
+ * we're going to do.
+ */
+static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
+{
+ struct atmel_lcdfb_info *sinfo = info->par;
+ unsigned int val;
+ u32 *pal;
+ int ret = 1;
+
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green
+ + 7471 * blue) >> 16;
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ if (regno < 16) {
+ pal = info->pseudo_palette;
+
+ val = chan_to_field(red, &info->var.red);
+ val |= chan_to_field(green, &info->var.green);
+ val |= chan_to_field(blue, &info->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_PSEUDOCOLOR:
+ if (regno < 256) {
+ val = ((red >> 11) & 0x001f);
+ val |= ((green >> 6) & 0x03e0);
+ val |= ((blue >> 1) & 0x7c00);
+
+ /*
+ * TODO: intensity bit. Maybe something like
+ * ~(red[10] ^ green[10] ^ blue[10]) & 1
+ */
+
+ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+ ret = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ dev_dbg(info->device, "%s\n", __func__);
+
+ atmel_lcdfb_update_dma(info, var);
+
+ return 0;
+}
+
+static struct fb_ops atmel_lcdfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = atmel_lcdfb_check_var,
+ .fb_set_par = atmel_lcdfb_set_par,
+ .fb_setcolreg = atmel_lcdfb_setcolreg,
+ .fb_pan_display = atmel_lcdfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+{
+ struct fb_info *info = dev_id;
+ struct atmel_lcdfb_info *sinfo = info->par;
+ u32 status;
+
+ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, status);
+ return IRQ_HANDLED;
+}
+
+static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+{
+ struct fb_info *info = sinfo->info;
+ int ret = 0;
+
+ memset_io(info->screen_base, 0, info->fix.smem_len);
+ info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+
+ dev_info(info->device,
+ "%luKiB frame buffer at %08lx (mapped at %p)\n",
+ (unsigned long)info->fix.smem_len / 1024,
+ (unsigned long)info->fix.smem_start,
+ info->screen_base);
+
+ /* Allocate colormap */
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret < 0)
+ dev_err(info->device, "Alloc color map failed\n");
+
+ return ret;
+}
+
+static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+{
+ if (sinfo->bus_clk)
+ clk_enable(sinfo->bus_clk);
+ clk_enable(sinfo->lcdc_clk);
+}
+
+static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+{
+ if (sinfo->bus_clk)
+ clk_disable(sinfo->bus_clk);
+ clk_disable(sinfo->lcdc_clk);
+}
+
+
+static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct fb_info *info;
+ struct atmel_lcdfb_info *sinfo;
+ struct atmel_lcdfb_info *pdata_sinfo;
+ struct resource *regs = NULL;
+ struct resource *map = NULL;
+ int ret;
+
+ dev_dbg(dev, "%s BEGIN\n", __func__);
+
+ ret = -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+ if (!info) {
+ dev_err(dev, "cannot allocate memory\n");
+ goto out;
+ }
+
+ sinfo = info->par;
+
+ if (dev->platform_data) {
+ pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+ sinfo->default_bpp = pdata_sinfo->default_bpp;
+ sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+ sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
+ sinfo->default_monspecs = pdata_sinfo->default_monspecs;
+ sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
+ sinfo->guard_time = pdata_sinfo->guard_time;
+ } else {
+ dev_err(dev, "cannot get default configuration\n");
+ goto free_info;
+ }
+ sinfo->info = info;
+ sinfo->pdev = pdev;
+
+ strcpy(info->fix.id, sinfo->pdev->name);
+ info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+ info->pseudo_palette = sinfo->pseudo_palette;
+ info->fbops = &atmel_lcdfb_ops;
+
+ memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+ info->fix = atmel_lcdfb_fix;
+
+ /* Enable LCDC Clocks */
+ if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) {
+ sinfo->bus_clk = clk_get(dev, "hck1");
+ if (IS_ERR(sinfo->bus_clk)) {
+ ret = PTR_ERR(sinfo->bus_clk);
+ goto free_info;
+ }
+ }
+ sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+ if (IS_ERR(sinfo->lcdc_clk)) {
+ ret = PTR_ERR(sinfo->lcdc_clk);
+ goto put_bus_clk;
+ }
+ atmel_lcdfb_start_clock(sinfo);
+
+ ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+ info->monspecs.modedb_len, info->monspecs.modedb,
+ sinfo->default_bpp);
+ if (!ret) {
+ dev_err(dev, "no suitable video mode found\n");
+ goto stop_clk;
+ }
+
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(dev, "resources unusable\n");
+ ret = -ENXIO;
+ goto stop_clk;
+ }
+
+ sinfo->irq_base = platform_get_irq(pdev, 0);
+ if (sinfo->irq_base < 0) {
+ dev_err(dev, "unable to get irq\n");
+ ret = sinfo->irq_base;
+ goto stop_clk;
+ }
+
+ /* Initialize video memory */
+ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (map) {
+ /* use a pre-allocated memory buffer */
+ info->fix.smem_start = map->start;
+ info->fix.smem_len = map->end - map->start + 1;
+ if (!request_mem_region(info->fix.smem_start,
+ info->fix.smem_len, pdev->name)) {
+ ret = -EBUSY;
+ goto stop_clk;
+ }
+
+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+ if (!info->screen_base)
+ goto release_intmem;
+ } else {
+ /* alocate memory buffer */
+ ret = atmel_lcdfb_alloc_video_memory(sinfo);
+ if (ret < 0) {
+ dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+ goto stop_clk;
+ }
+ }
+
+ /* LCDC registers */
+ info->fix.mmio_start = regs->start;
+ info->fix.mmio_len = regs->end - regs->start + 1;
+
+ if (!request_mem_region(info->fix.mmio_start,
+ info->fix.mmio_len, pdev->name)) {
+ ret = -EBUSY;
+ goto free_fb;
+ }
+
+ sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+ if (!sinfo->mmio) {
+ dev_err(dev, "cannot map LCDC registers\n");
+ goto release_mem;
+ }
+
+ /* interrupt */
+ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+ if (ret) {
+ dev_err(dev, "request_irq failed: %d\n", ret);
+ goto unmap_mmio;
+ }
+
+ ret = atmel_lcdfb_init_fbinfo(sinfo);
+ if (ret < 0) {
+ dev_err(dev, "init fbinfo failed: %d\n", ret);
+ goto unregister_irqs;
+ }
+
+ /*
+ * This makes sure that our colour bitfield
+ * descriptors are correctly initialised.
+ */
+ atmel_lcdfb_check_var(&info->var, info);
+
+ ret = fb_set_var(info, &info->var);
+ if (ret) {
+ dev_warn(dev, "unable to set display parameters\n");
+ goto free_cmap;
+ }
+
+ dev_set_drvdata(dev, info);
+
+ /*
+ * Tell the world that we're ready to go
+ */
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+ goto free_cmap;
+ }
+
+ /* Power up the LCDC screen */
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(1);
+
+ dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+ info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+
+ return 0;
+
+
+free_cmap:
+ fb_dealloc_cmap(&info->cmap);
+unregister_irqs:
+ free_irq(sinfo->irq_base, info);
+unmap_mmio:
+ iounmap(sinfo->mmio);
+release_mem:
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+free_fb:
+ if (map)
+ iounmap(info->screen_base);
+ else
+ atmel_lcdfb_free_video_memory(sinfo);
+
+release_intmem:
+ if (map)
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+stop_clk:
+ atmel_lcdfb_stop_clock(sinfo);
+ clk_put(sinfo->lcdc_clk);
+put_bus_clk:
+ if (sinfo->bus_clk)
+ clk_put(sinfo->bus_clk);
+free_info:
+ framebuffer_release(info);
+out:
+ dev_dbg(dev, "%s FAILED\n", __func__);
+ return ret;
+}
+
+static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct atmel_lcdfb_info *sinfo = info->par;
+
+ if (!sinfo)
+ return 0;
+
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+ unregister_framebuffer(info);
+ atmel_lcdfb_stop_clock(sinfo);
+ clk_put(sinfo->lcdc_clk);
+ if (sinfo->bus_clk)
+ clk_put(sinfo->bus_clk);
+ fb_dealloc_cmap(&info->cmap);
+ free_irq(sinfo->irq_base, info);
+ iounmap(sinfo->mmio);
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+ iounmap(info->screen_base);
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ } else {
+ atmel_lcdfb_free_video_memory(sinfo);
+ }
+
+ dev_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+
+ return 0;
+}
+
+static struct platform_driver atmel_lcdfb_driver = {
+ .remove = __exit_p(atmel_lcdfb_remove),
+ .driver = {
+ .name = "atmel_lcdfb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init atmel_lcdfb_init(void)
+{
+ return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
+}
+
+static void __exit atmel_lcdfb_exit(void)
+{
+ platform_driver_unregister(&atmel_lcdfb_driver);
+}
+
+module_init(atmel_lcdfb_init);
+module_exit(atmel_lcdfb_exit);
+
+MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index aa3935df852a..63b85bf81a65 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -19,13 +19,6 @@ config VGA_CONSOLE
Say Y.
-# if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then
-# bool ' Allow VGA on any bus?' CONFIG_VGA_HOSE
-# if [ "$CONFIG_VGA_HOSE" = "y" ]; then
-# define_bool CONFIG_DUMMY_CONSOLE y
-# fi
-# fi
-
config VGACON_SOFT_SCROLLBACK
bool "Enable Scrollback Buffer in System RAM"
depends on VGA_CONSOLE
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index f577bd80e020..03cfb7ac5733 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/video/softcursor.c
+ * linux/drivers/video/console/softcursor.c
*
* Generic software cursor for frame buffer devices
*
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 08d4e11d9121..38c2e2558f5e 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1236,6 +1236,10 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
#elif defined(__arm__) || defined(__sh__) || defined(__m32r__)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__avr32__)
+ vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot)
+ & ~_PAGE_CACHABLE)
+ | (_PAGE_BUFFER | _PAGE_DIRTY));
#elif defined(__ia64__)
if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 7e760197cf29..1a7d7789d877 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1717,7 +1717,7 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info)
* @info: pointer to device specific info structure
*
* DESCRIPTION:
- * Sets the the user monitor's horizontal and vertical
+ * Sets the user monitor's horizontal and vertical
* frequency limits
*/
static void __devinit i810_init_monspecs(struct fb_info *info)
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
index a5690a5f29d5..9445cdb759b1 100644
--- a/drivers/video/matrox/matroxfb_Ti3026.c
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -72,7 +72,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
index a5c825d99466..c57aaadf410c 100644
--- a/drivers/video/matrox/matroxfb_accel.c
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -70,7 +70,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index cb2aa402ddfd..c8559a756b75 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -93,7 +93,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index 18886b629cb1..5948e54b9ef9 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -78,7 +78,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index f297c7b14a41..aff11bbf59a7 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -150,7 +150,8 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
M = pll & 0xFF;
N = (pll >> 8) & 0xFF;
if (((par->Chipset & 0xfff0) == 0x0290) ||
- ((par->Chipset & 0xfff0) == 0x0390)) {
+ ((par->Chipset & 0xfff0) == 0x0390) ||
+ ((par->Chipset & 0xfff0) == 0x02E0)) {
MB = 1;
NB = 1;
} else {
@@ -963,6 +964,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
if (((par->Chipset & 0xfff0) == 0x0090) ||
((par->Chipset & 0xfff0) == 0x01D0) ||
+ ((par->Chipset & 0xfff0) == 0x02E0) ||
((par->Chipset & 0xfff0) == 0x0290))
regions = 15;
for(i = 0; i < regions; i++) {
@@ -1275,6 +1277,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
0x00100000);
break;
case 0x0090:
+ case 0x02E0:
case 0x0290:
NV_WR32(par->PRAMDAC, 0x0608,
NV_RD32(par->PRAMDAC, 0x0608) |
@@ -1352,6 +1355,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
} else {
if (((par->Chipset & 0xfff0) == 0x0090) ||
((par->Chipset & 0xfff0) == 0x01D0) ||
+ ((par->Chipset & 0xfff0) == 0x02E0) ||
((par->Chipset & 0xfff0) == 0x0290)) {
for (i = 0; i < 60; i++) {
NV_WR32(par->PGRAPH,
@@ -1403,6 +1407,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
} else {
if ((par->Chipset & 0xfff0) == 0x0090 ||
(par->Chipset & 0xfff0) == 0x01D0 ||
+ (par->Chipset & 0xfff0) == 0x02E0 ||
(par->Chipset & 0xfff0) == 0x0290) {
NV_WR32(par->PGRAPH, 0x0DF0,
NV_RD32(par->PFB, 0x0200));
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 7c36b5fe582e..41f63658572f 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -37,7 +37,6 @@
#include "nv_proto.h"
#include "nv_dma.h"
-#undef CONFIG_FB_NVIDIA_DEBUG
#ifdef CONFIG_FB_NVIDIA_DEBUG
#define NVTRACE printk
#else
@@ -1243,6 +1242,7 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info)
case 0x0140: /* GeForce 6600 */
case 0x0160: /* GeForce 6200 */
case 0x01D0: /* GeForce 7200, 7300, 7400 */
+ case 0x02E0: /* GeForce 7300 GT */
case 0x0090: /* GeForce 7800 */
case 0x0210: /* GeForce 6800 */
case 0x0220: /* GeForce 6200 */
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 1ac5264bb2c1..ab5e66890e4e 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -204,17 +204,6 @@ static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a)
}
#endif
-static void wait_pm2(struct pm2fb_par* par) {
-
- WAIT_FIFO(par, 1);
- pm2_WR(par, PM2R_SYNC, 0);
- mb();
- do {
- while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0);
- rmb();
- } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
-}
-
/*
* partial products for the supported horizontal resolutions.
*/
@@ -1050,13 +1039,30 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info)
return 0;
}
+static int pm2fb_sync(struct fb_info *info)
+{
+ struct pm2fb_par *par = info->par;
+
+ WAIT_FIFO(par, 1);
+ pm2_WR(par, PM2R_SYNC, 0);
+ mb();
+ do {
+ while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
+ udelay(10);
+ rmb();
+ } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
+
+ return 0;
+}
+
/*
* block operation. copy=0: rectangle fill, copy=1: rectangle copy.
*/
-static void pm2fb_block_op(struct pm2fb_par* par, int copy,
+static void pm2fb_block_op(struct fb_info* info, int copy,
s32 xsrc, s32 ysrc,
s32 x, s32 y, s32 w, s32 h,
u32 color) {
+ struct pm2fb_par *par = info->par;
if (!w || !h)
return;
@@ -1076,13 +1082,11 @@ static void pm2fb_block_op(struct pm2fb_par* par, int copy,
(x<xsrc ? PM2F_INCREASE_X : 0) |
(y<ysrc ? PM2F_INCREASE_Y : 0) |
(copy ? 0 : PM2F_RENDER_FASTFILL));
- wait_pm2(par);
}
static void pm2fb_fillrect (struct fb_info *info,
const struct fb_fillrect *region)
{
- struct pm2fb_par *par = info->par;
struct fb_fillrect modded;
int vxres, vyres;
u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
@@ -1116,7 +1120,7 @@ static void pm2fb_fillrect (struct fb_info *info,
color |= color << 16;
if(info->var.bits_per_pixel != 24)
- pm2fb_block_op(par, 0, 0, 0,
+ pm2fb_block_op(info, 0, 0, 0,
modded.dx, modded.dy,
modded.width, modded.height, color);
else
@@ -1126,7 +1130,6 @@ static void pm2fb_fillrect (struct fb_info *info,
static void pm2fb_copyarea(struct fb_info *info,
const struct fb_copyarea *area)
{
- struct pm2fb_par *par = info->par;
struct fb_copyarea modded;
u32 vxres, vyres;
@@ -1156,7 +1159,7 @@ static void pm2fb_copyarea(struct fb_info *info,
if(modded.dy + modded.height > vyres)
modded.height = vyres - modded.dy;
- pm2fb_block_op(par, 1, modded.sx, modded.sy,
+ pm2fb_block_op(info, 1, modded.sx, modded.sy,
modded.dx, modded.dy,
modded.width, modded.height, 0);
}
@@ -1177,6 +1180,7 @@ static struct fb_ops pm2fb_ops = {
.fb_fillrect = pm2fb_fillrect,
.fb_copyarea = pm2fb_copyarea,
.fb_imageblit = cfb_imageblit,
+ .fb_sync = pm2fb_sync,
};
/*
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index bd787e80177d..6c4dfcb0feb9 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -1,55 +1,25 @@
/*
* linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
- *
- * Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
+ *
+ * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
+ *
+ * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
+ * based on pm2fb.c
+ *
* Based on code written by:
- * Sven Luther, <luther@dpt-info.u-strasbg.fr>
- * Alan Hourihane, <alanh@fairlite.demon.co.uk>
- * Russell King, <rmk@arm.linux.org.uk>
+ * Sven Luther, <luther@dpt-info.u-strasbg.fr>
+ * Alan Hourihane, <alanh@fairlite.demon.co.uk>
+ * Russell King, <rmk@arm.linux.org.uk>
* Based on linux/drivers/video/skeletonfb.c:
* Copyright (C) 1997 Geert Uytterhoeven
* Based on linux/driver/video/pm2fb.c:
- * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
- * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
+ * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
- * $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $
- *
- * CHANGELOG:
- * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
- * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
- * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
- * Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
- * Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
- * Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix.
- * Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG.
- * Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL.
- * Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning.
- * Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option.
- * Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support.
- * Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates.
- * Fri Apr 6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup
- * Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added).
- * Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian.
- * Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov).
- * Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes.
- * Thu Mar 8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option.
- * Tue Mar 6 21:25:04 CET 2001, v 1.2.1: Better acceleration support.
- * Mon Mar 5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove)
- * Mon Mar 5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix.
- * Sun Mar 4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes.
- * Fri Mar 2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4
- * Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested)
- * Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode
- * Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up
- * Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix
- * Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default
- * Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix
- * Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning
- * Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
*/
#include <linux/module.h>
@@ -58,856 +28,155 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/ctype.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-#include <video/pm3fb.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <video/pm3fb.h>
-#ifdef CONFIG_FB_OF
-#include <asm/prom.h>
+#if !defined(CONFIG_PCI)
+#error "Only generic PCI cards supported."
#endif
-/* ************************************* */
-/* ***** The various "global" data ***** */
-/* ************************************* */
-
-/* those will need a rework for multiple board support */
-/* Driver name */
-static const char permedia3_name[16] = "Permedia3";
-
-/* the fb_par struct, mandatory */
-struct pm3fb_par {
- u32 pixclock; /* pixclock in KHz */
-
- u32 width; /* width of virtual screen */
- u32 height; /* height of virtual screen */
-
- u32 hsstart; /* horiz. sync start */
- u32 hsend; /* horiz. sync end */
- u32 hbend; /* horiz. blank end (also gate end) */
- u32 htotal; /* total width (w/ sync & blank) */
-
- u32 vsstart; /* vert. sync start */
- u32 vsend; /* vert. sync end */
- u32 vbend; /* vert. blank end */
- u32 vtotal; /* total height (w/ sync & blank) */
-
- u32 stride; /* screen stride */
- u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */
- /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */
- u32 depth; /* screen depth (8, 12, 15, 16 or 32) */
- u32 video; /* video control (hsync,vsync) */
-};
-
-/* memory timings */
-struct pm3fb_timings
-{
- unsigned long caps;
- unsigned long timings;
- unsigned long control;
- unsigned long refresh;
- unsigned long powerdown;
-};
-typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
-#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
-#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
-
-/* the fb_info struct, mandatory */
-struct pm3fb_info {
- struct fb_info_gen gen;
- unsigned long board_num; /* internal board number */
- unsigned long use_current;
- struct pm3fb_par *current_par;
- struct pci_dev *dev; /* PCI device */
- unsigned long board_type; /* index in the cardbase */
- unsigned char *fb_base; /* framebuffer memory base */
- u32 fb_size; /* framebuffer memory size */
- unsigned char *p_fb; /* physical address of frame buffer */
- unsigned char *v_fb; /* virtual address of frame buffer */
- unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */
- unsigned char *vIOBase; /* address of registers after ioremap() */
- struct {
- u8 transp;
- u8 red;
- u8 green;
- u8 blue;
- } palette[256];
- union {
-#ifdef FBCON_HAS_CFB16
- u16 cmap12[16]; /* RGBA 4444 */
- u16 cmap15[16]; /* RGBA 5551 */
- u16 cmap16[16]; /* RGBA 5650 */
-#endif
-#ifdef FBCON_HAS_CFB32
- u32 cmap32[16];
+#undef PM3FB_MASTER_DEBUG
+#ifdef PM3FB_MASTER_DEBUG
+#define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
#endif
- } cmap;
- struct pm3fb_timings memt;
-};
-
-/* regular resolution database*/
-static struct {
- char name[16];
- struct pm3fb_par user_mode;
-} mode_base[] __initdata = {
- {
- "default-800x600", {
- 49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}}, {
- "1024x768-74", {
- 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
- 806, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}}, {
- "1024x768-74-32", {
- 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
- 806, 1024, 0, 32,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_32BIT}},
-/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
- {
- "SGI1600SW", {
- 108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
- 1056, 1600, 0, 8,
- PM3VideoControl_ENABLE|
- PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
- PM3VideoControl_PIXELSIZE_32BIT}},
-/* ##### auto-generated mode, by fbtimings2pm3 */
-/* Generated mode : "640x480-60" */
- {
- "640x480-60", {
- 25174, 640, 480, 16, 112, 160, 800, 10, 12, 45,
- 525, 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-72" */
- {
- "640x480-72", {
- 31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520,
- 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-75" */
- {
- "640x480-75", {
- 31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500,
- 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-90" */
- {
- "640x480-90", {
- 39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533,
- 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-100" */
- {
- "640x480-100", {
- 44899, 640, 480, 32, 160, 208, 848, 22, 34, 51,
- 531, 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-48-lace" */
-/* INTERLACED NOT SUPPORTED
- {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "800x600-56" */
- {
- "800x600-56", {
- 35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-60" */
- {
- "800x600-60", {
- 40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-70" */
- {
- "800x600-70", {
- 44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36,
- 636, 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-72" */
- {
- "800x600-72", {
- 50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66,
- 666, 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-75" */
- {
- "800x600-75", {
- 49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-90" */
- {
- "800x600-90", {
- 56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-100", from /etc/fb.modes */
-/* DISABLED, hsstart == 0
- {
- "800x600-100", {
- 67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "800x600-100", from ??? */
- {
- "800x600-100", {
- 69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8,
- PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
- PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-43-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1024x768-60" */
- {
- "1024x768-60", {
- 64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38,
- 806, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-70" */
- {
- "1024x768-70", {
- 74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38,
- 806, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-72" */
- {
- "1024x768-72", {
- 74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38,
- 806, 10224, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-75" */
- {
- "1024x768-75", {
- 78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32,
- 800, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-90" */
- {
- "1024x768-90", {
- 100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77,
- 845, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-100", from /etc/fb.modes */
-/* DISABLED, vsstart == 0
- {
- "1024x768-100", {
- 109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792,
- 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "1024x768-100", from ??? */
- {
- "1024x768-100", {
- 115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8,
- PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
- PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-43-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-47-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-60" */
- {
- "1152x864-60", {
- 80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52,
- 916, 1152, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-70" */
- {
- "1152x864-70", {
- 100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81,
- 945, 1152, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-75" */
- {
- "1152x864-75", {
- 109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138,
- 1002, 1152, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-80" */
- {
- "1152x864-80", {
- 109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94,
- 958, 1152, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-43-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-47-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-60" */
- {
- "1280x1024-60", {
- 107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42,
- 1066, 1280, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-70" */
- {
- "1280x1024-70", {
- 125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42,
- 1066, 1280, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-74" */
- {
- "1280x1024-74", {
- 134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40,
- 1064, 1280, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-75" */
- {
- "1280x1024-75", {
- 134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42,
- 1066, 1280, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-60" */
- {
- "1600x1200-60", {
- 155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70,
- 1270, 1600, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-66" */
- {
- "1600x1200-66", {
- 171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53,
- 1253, 1600, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-76" */
- {
- "1600x1200-76", {
- 197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50,
- 1250, 1600, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* ##### end of auto-generated mode */
- {
- "\0",}
-};
-/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */
-static struct pm3fb_info fb_info[PM3_MAX_BOARD];
-static struct pm3fb_par current_par[PM3_MAX_BOARD];
-static int current_par_valid[PM3_MAX_BOARD];
-/* to allow explicit filtering of board */
-short bus[PM3_MAX_BOARD];
-short slot[PM3_MAX_BOARD];
-short func[PM3_MAX_BOARD];
-short disable[PM3_MAX_BOARD];
-short noaccel[PM3_MAX_BOARD];
-char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
-short depth[PM3_MAX_BOARD];
-short flatpanel[PM3_MAX_BOARD];
-static struct display disp[PM3_MAX_BOARD];
-static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
-short printtimings = 0;
-short forcesize[PM3_MAX_BOARD];
-
-/* ********************* */
-/* ***** prototype ***** */
-/* ********************* */
-/* card-specific */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
-/* permedia3-specific */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
- unsigned long r);
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */
- unsigned long refclock, /* In kHz units */
- unsigned char *prescale, /* ClkPreScale */
- unsigned char *feedback, /* ClkFeedBackScale */
- unsigned char *postscale
- /* ClkPostScale */ );
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
- unsigned long depth, int v);
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
- unsigned long depth, int v);
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
-#endif
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
- struct pm3fb_par *curpar);
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
-/* accelerated permedia3-specific */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width);
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width);
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width);
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
- int sy, int sx,
- int dy, int dx, int height, int width);
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
- int c, int yy, int xx);
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy,
- int xx);
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy);
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* pre-init */
-static void pm3fb_mode_setup(char *mode, unsigned long board_num);
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
-static void pm3fb_real_setup(char *options);
-/* fbdev */
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
- const void *par, struct fb_info_gen *info);
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
- void *par, struct fb_info_gen *info);
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
- const void *par, struct fb_info_gen *info);
-static void pm3fb_get_par(void *par, struct fb_info_gen *info);
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
- unsigned char regno, unsigned char r,
- unsigned char g, unsigned char b);
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *info);
-static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info);
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
-static void pm3fb_set_disp(const void *par, struct display *disp,
- struct fb_info_gen *info);
-static void pm3fb_detect(void);
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
- struct fb_info_gen *info);
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
-
-
-/* the struct that hold them together */
-struct fbgen_hwswitch pm3fb_switch = {
- pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
- pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg,
- pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
-};
+/*
+ * Driver data
+ */
+static char *mode_option __devinitdata;
-static struct fb_ops pm3fb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = fbgen_get_fix,
- .fb_get_var = fbgen_get_var,
- .fb_set_var = fbgen_set_var,
- .fb_get_cmap = fbgen_get_cmap,
- .fb_set_cmap = fbgen_set_cmap,
- .fb_setcolreg = pm3fb_setcolreg,
- .fb_pan_display =fbgen_pan_display,
- .fb_blank = fbgen_blank,
- .fb_ioctl = pm3fb_ioctl,
-};
+/*
+ * If your driver supports multiple boards, you should make the
+ * below data types arrays, or allocate them dynamically (using kmalloc()).
+ */
-#ifdef PM3FB_USE_ACCEL
-#ifdef FBCON_HAS_CFB32
-static struct display_switch pm3fb_cfb32 = {
- fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear,
- pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
- NULL /* cursor() */ , NULL /* set_font() */ ,
- pm3fb_cfb32_clear_margins,
- FONTWIDTHRANGE(1, 16) /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static struct display_switch pm3fb_cfb16 = {
- fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear,
- pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
- NULL /* cursor() */ , NULL /* set_font() */ ,
- pm3fb_cfb16_clear_margins,
- FONTWIDTHRANGE(1, 16) /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static struct display_switch pm3fb_cfb8 = {
- fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear,
- pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
- NULL /* cursor() */ , NULL /* set_font() */ ,
- pm3fb_cfb8_clear_margins,
- FONTWIDTHRANGE(1, 16) /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB8 */
-#endif /* PM3FB_USE_ACCEL */
-
-/* ****************************** */
-/* ***** card-specific data ***** */
-/* ****************************** */
-struct pm3fb_card_timings {
- unsigned long memsize; /* 0 for last value (i.e. default) */
- struct pm3fb_timings memt;
+/*
+ * This structure defines the hardware state of the graphics card. Normally
+ * you place this in a header file in linux/include/video. This file usually
+ * also includes register information. That allows other driver subsystems
+ * and userland applications the ability to use the same header file to
+ * avoid duplicate work and easy porting of software.
+ */
+struct pm3_par {
+ unsigned char __iomem *v_regs;/* virtual address of p_regs */
+ u32 video; /* video flags before blanking */
+ u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */
+ u32 palette[16];
};
-static struct pm3fb_card_timings t_FormacProFormance3[] = {
- { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
- { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
+/*
+ * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
+ * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
+ * to get a fb_var_screeninfo. Otherwise define a default var as well.
+ */
+static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
+ .id = "Permedia3",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .xpanstep = 1,
+ .ypanstep = 1,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
};
-static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
- { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
- { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
-};
+/*
+ * Utility functions
+ */
-static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
- { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
- { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
-};
+static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
+{
+ return fb_readl(par->v_regs + off);
+}
-static struct {
- char cardname[32]; /* recognized card name */
- u16 subvendor; /* subvendor of the card */
- u16 subdevice; /* subdevice of the card */
- u8 func; /* function of the card to which the extra init apply */
- void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
- struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
-} cardbase[] = {
- { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
- { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
- t_AppianJeronimo2000
- },
- { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
- t_AppianJeronimo2000
- },
- { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
- t_FormacProFormance3
- },
- { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
- { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
- t_3DLabsOxygenVX1
- },
- { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
- { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
- { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
- { "\0", 0x0, 0x0, 0, NULL, NULL }
-};
+static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
+{
+ fb_writel(v, par->v_regs + off);
+}
-/* ********************************** */
-/* ***** card-specific function ***** */
-/* ********************************** */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
-{ /* the appian j2000 require more initialization of the second head */
- /* l_fb_info must point to the _second_ head of the J2000 */
-
- DTRACE;
-
- l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
-
- pm3fb_write_memory_timings(l_fb_info);
+static inline void PM3_WAIT(struct pm3_par *par, u32 n)
+{
+ while (PM3_READ_REG(par, PM3InFIFOSpace) < n);
}
-/* *************************************** */
-/* ***** permedia3-specific function ***** */
-/* *************************************** */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_SLOW_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
{
- l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
- l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
- l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl);
- l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh);
- l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown);
-
- if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) ||
- (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) ||
- (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) ||
- (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) ||
- (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
- {
- printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
- return(pm3fb_try_memory_timings(l_fb_info));
+ if (par->v_regs) {
+ mb();
+ PM3_WAIT(par, 1);
+ wmb();
+ PM3_WRITE_REG(par, off, v);
}
- return(pm3fb_timing_ok);
}
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_SET_INDEX(struct pm3_par *par, unsigned index)
{
- if (cardbase[l_fb_info->board_type].c_memt)
- {
- int i = 0, done = 0;
- while (!done)
- {
- if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
- || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
- { /* will use the 0-sized timings by default */
- done = 1;
- l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
- printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
- l_fb_info->board_num,
- cardbase[l_fb_info->board_type].cardname,
- cardbase[l_fb_info->board_type].c_memt[i].memsize);
- pm3fb_write_memory_timings(l_fb_info);
- return(pm3fb_timing_retry);
- }
- i++;
- }
- } else
- return(pm3fb_timing_problem);
- return(pm3fb_timing_ok);
+ PM3_SLOW_WRITE_REG(par, PM3RD_IndexHigh, (index >> 8) & 0xff);
+ PM3_SLOW_WRITE_REG(par, PM3RD_IndexLow, index & 0xff);
}
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
{
- unsigned char m, n, p;
- unsigned long clockused;
-
- PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps);
- PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings);
- PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control);
- PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh);
- PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown);
-
- clockused =
- pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m,
- &n, &p);
-
- PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m);
- PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n);
- PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p);
- PM3_WRITE_DAC_REG(PM3RD_KClkControl,
- PM3RD_KClkControl_STATE_RUN |
- PM3RD_KClkControl_SOURCE_PLL |
- PM3RD_KClkControl_ENABLE);
- PM3_WRITE_DAC_REG(PM3RD_MClkControl,
- PM3RD_MClkControl_STATE_RUN |
- PM3RD_MClkControl_SOURCE_KCLK |
- PM3RD_MClkControl_ENABLE);
- PM3_WRITE_DAC_REG(PM3RD_SClkControl,
- PM3RD_SClkControl_STATE_RUN |
- PM3RD_SClkControl_SOURCE_PCLK |
- PM3RD_SClkControl_ENABLE);
+ PM3_SET_INDEX(par, r);
+ wmb();
+ PM3_WRITE_REG(par, PM3RD_IndexedData, v);
}
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
- unsigned long r)
+static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
+ unsigned char r, unsigned char g, unsigned char b)
{
- DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)),
- "l_fb_info->vIOBase mapped in read dac reg\n");
- PM3_SET_INDEX(r);
- mb();
- return (PM3_READ_REG(PM3RD_IndexedData));
+ PM3_SLOW_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
+ PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, r);
+ PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, g);
+ PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, b);
+}
+
+static void pm3fb_clear_colormap(struct pm3_par *par,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ int i;
+
+ for (i = 0; i < 256 ; i++) /* fill color map with white */
+ pm3fb_set_color(par, i, r, g, b);
+
}
/* Calculating various clock parameter */
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */
- unsigned long refclock, /* In kHz units */
- unsigned char *prescale, /* ClkPreScale */
- unsigned char *feedback, /* ClkFeedBackScale */
- unsigned char *postscale
- /* ClkPostScale */ )
+static void pm3fb_calculate_clock(unsigned long reqclock,
+ unsigned char *prescale,
+ unsigned char *feedback,
+ unsigned char *postscale)
{
int f, pre, post;
unsigned long freq;
long freqerr = 1000;
- unsigned long actualclock = 0;
-
- DTRACE;
+ long currerr;
for (f = 1; f < 256; f++) {
for (pre = 1; pre < 256; pre++) {
for (post = 0; post < 5; post++) {
- freq =
- ((2 * refclock * f) /
- (pre * (1 << post)));
- if ((reqclock > freq - freqerr)
- && (reqclock < freq + freqerr)) {
- freqerr =
- (reqclock >
- freq) ? reqclock -
- freq : freq - reqclock;
+ freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
+ currerr = (reqclock > freq)
+ ? reqclock - freq
+ : freq - reqclock;
+ if (currerr < freqerr) {
+ freqerr = currerr;
*feedback = f;
*prescale = pre;
*postscale = post;
- actualclock = freq;
}
}
}
}
-
- return (actualclock);
}
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
- unsigned long depth, int v)
+static inline int pm3fb_shift_bpp(unsigned long depth, int v)
{
- DTRACE;
-
switch (depth) {
case 8:
return (v >> 4);
@@ -918,181 +187,59 @@ static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
case 32:
return (v >> 2);
}
- DPRINTK(1, "Unsupported depth %ld\n", depth);
- return (0);
-}
-
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
- unsigned long depth, int v)
-{
- DTRACE;
-
- switch (depth) {
- case 8:
- return (v << 4);
- case 12:
- case 15:
- case 16:
- return (v << 3);
- case 32:
- return (v << 2);
- }
- DPRINTK(1, "Unsupported depth %ld\n", depth);
- return (0);
-}
-
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info)
-{
- DTRACE;
-
- l_fb_info->vIOBase =
- ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE);
- l_fb_info->v_fb =
- ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size);
- DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n",
- (unsigned long) l_fb_info->pIOBase,
- (unsigned long) l_fb_info->vIOBase,
- (unsigned long) l_fb_info->p_fb,
- (unsigned long) l_fb_info->v_fb);
-}
-
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info)
-{
- DTRACE;
-
- iounmap(l_fb_info->vIOBase);
- iounmap(l_fb_info->v_fb);
- l_fb_info->vIOBase = (unsigned char *) -1;
- l_fb_info->v_fb = (unsigned char *) -1;
-}
-
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info)
-{
- DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0));
- DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1));
- DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n",
- PM3_READ_REG(PM3ByAperture1Mode));
- DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n",
- PM3_READ_REG(PM3ByAperture2Mode));
- DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig));
- DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis));
- DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal));
- DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd));
- DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd));
- DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd));
- DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart));
- DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n",
- PM3_READ_REG(PM3MemBypassWriteMask));
- DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n",
- PM3_READ_REG(PM3RD_IndexControl));
- DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase));
- DPRINTK(2, "PM3ScreenStride: 0x%08x\n",
- PM3_READ_REG(PM3ScreenStride));
- DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl));
- DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal));
- DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd));
- DPRINTK(2, "PM3VideoControl: 0x%08x\n",
- PM3_READ_REG(PM3VideoControl));
- DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd));
- DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart));
-
- DPRINTK(2, "PM3RD_ColorFormat: %ld\n",
- PM3_READ_DAC_REG(PM3RD_ColorFormat));
- DPRINTK(2, "PM3RD_DACControl: %ld\n",
- PM3_READ_DAC_REG(PM3RD_DACControl));
- DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n",
- PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale));
- DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n",
- PM3_READ_DAC_REG(PM3RD_DClk0PostScale));
- DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n",
- PM3_READ_DAC_REG(PM3RD_DClk0PreScale));
- DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n",
- PM3_READ_DAC_REG(PM3RD_IndexControl));
- DPRINTK(2, "PM3RD_MiscControl: %ld\n",
- PM3_READ_DAC_REG(PM3RD_MiscControl));
- DPRINTK(2, "PM3RD_PixelSize: %ld\n",
- PM3_READ_DAC_REG(PM3RD_PixelSize));
- DPRINTK(2, "PM3RD_SyncControl: %ld\n",
- PM3_READ_DAC_REG(PM3RD_SyncControl));
-}
-
-#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info)
-{
- u16 subvendor, subdevice;
-
- if ((!pci_read_config_word
- (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
- &&
- (!pci_read_config_word
- (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
- /* well, nothing... */
- } else {
- subvendor = subdevice = (u16)-1;
- }
-
- printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice);
- printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemCaps));
- printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemTimings));
- printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemControl));
- printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemRefresh));
- printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemPowerDown));
+ DPRINTK("Unsupported depth %ld\n", depth);
+ return 0;
}
/* write the mode to registers */
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
+static void pm3fb_write_mode(struct fb_info *info)
{
+ struct pm3_par *par = info->par;
char tempsync = 0x00, tempmisc = 0x00;
- DTRACE;
-
- PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
- PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000);
- PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000);
- PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007);
-
- PM3_SLOW_WRITE_REG(PM3HTotal,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->htotal -
- 1));
- PM3_SLOW_WRITE_REG(PM3HsEnd,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->hsend));
- PM3_SLOW_WRITE_REG(PM3HsStart,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->
+ const u32 hsstart = info->var.right_margin;
+ const u32 hsend = hsstart + info->var.hsync_len;
+ const u32 hbend = hsend + info->var.left_margin;
+ const u32 xres = (info->var.xres + 31) & ~31;
+ const u32 htotal = xres + hbend;
+ const u32 vsstart = info->var.lower_margin;
+ const u32 vsend = vsstart + info->var.vsync_len;
+ const u32 vbend = vsend + info->var.upper_margin;
+ const u32 vtotal = info->var.yres + vbend;
+ const u32 width = (info->var.xres_virtual + 7) & ~7;
+
+ PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
+ PM3_SLOW_WRITE_REG(par, PM3Aperture0, 0x00000000);
+ PM3_SLOW_WRITE_REG(par, PM3Aperture1, 0x00000000);
+ PM3_SLOW_WRITE_REG(par, PM3FIFODis, 0x00000007);
+
+ PM3_SLOW_WRITE_REG(par, PM3HTotal,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ htotal - 1));
+ PM3_SLOW_WRITE_REG(par, PM3HsEnd,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ hsend));
+ PM3_SLOW_WRITE_REG(par, PM3HsStart,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
hsstart));
- PM3_SLOW_WRITE_REG(PM3HbEnd,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->hbend));
- PM3_SLOW_WRITE_REG(PM3HgEnd,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->hbend));
- PM3_SLOW_WRITE_REG(PM3ScreenStride,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->stride));
- PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1);
- PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1);
- PM3_SLOW_WRITE_REG(PM3VsStart,
- l_fb_info->current_par->vsstart - 1);
- PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend);
-
- switch (l_fb_info->current_par->depth) {
+ PM3_SLOW_WRITE_REG(par, PM3HbEnd,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ hbend));
+ PM3_SLOW_WRITE_REG(par, PM3HgEnd,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ hbend));
+ PM3_SLOW_WRITE_REG(par, PM3ScreenStride,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ width));
+ PM3_SLOW_WRITE_REG(par, PM3VTotal, vtotal - 1);
+ PM3_SLOW_WRITE_REG(par, PM3VsEnd, vsend - 1);
+ PM3_SLOW_WRITE_REG(par, PM3VsStart, vsstart - 1);
+ PM3_SLOW_WRITE_REG(par, PM3VbEnd, vbend);
+
+ switch (info->var.bits_per_pixel) {
case 8:
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_8BIT);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_8BIT);
break;
@@ -1100,15 +247,15 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
case 15:
case 16:
#ifndef __BIG_ENDIAN
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_16BIT);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_16BIT);
#else
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_16BIT |
PM3ByApertureMode_BYTESWAP_BADC);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_16BIT |
PM3ByApertureMode_BYTESWAP_BADC);
#endif /* ! __BIG_ENDIAN */
@@ -1116,23 +263,23 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
case 32:
#ifndef __BIG_ENDIAN
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_32BIT);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_32BIT);
#else
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_32BIT |
PM3ByApertureMode_BYTESWAP_DCBA);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_32BIT |
PM3ByApertureMode_BYTESWAP_DCBA);
#endif /* ! __BIG_ENDIAN */
break;
default:
- DPRINTK(1, "Unsupported depth %d\n",
- l_fb_info->current_par->depth);
+ DPRINTK("Unsupported depth %d\n",
+ info->var.bits_per_pixel);
break;
}
@@ -1143,95 +290,86 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
* sync options in PM3RD_SyncControl. --rmk
*/
{
- unsigned int video = l_fb_info->current_par->video;
+ unsigned int video = par->video;
video &= ~(PM3VideoControl_HSYNC_MASK |
PM3VideoControl_VSYNC_MASK);
video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
PM3VideoControl_VSYNC_ACTIVE_HIGH;
- PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+ PM3_SLOW_WRITE_REG(par, PM3VideoControl, video);
}
- PM3_SLOW_WRITE_REG(PM3VClkCtl,
- (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC));
- PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
- PM3_SLOW_WRITE_REG(PM3ChipConfig,
- (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD));
+ PM3_SLOW_WRITE_REG(par, PM3VClkCtl,
+ (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
+ PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+ PM3_SLOW_WRITE_REG(par, PM3ChipConfig,
+ (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
{
- unsigned char m; /* ClkPreScale */
- unsigned char n; /* ClkFeedBackScale */
- unsigned char p; /* ClkPostScale */
- (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p);
-
- DPRINTK(2,
- "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n",
- l_fb_info->current_par->pixclock, (int) m, (int) n,
- (int) p);
-
- PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m);
- PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n);
- PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p);
+ unsigned char uninitialized_var(m); /* ClkPreScale */
+ unsigned char uninitialized_var(n); /* ClkFeedBackScale */
+ unsigned char uninitialized_var(p); /* ClkPostScale */
+ unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
+
+ (void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
+
+ DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
+ pixclock, (int) m, (int) n, (int) p);
+
+ PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
+ PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
+ PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
}
/*
- PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00);
+ PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
*/
/*
- PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
+ PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
*/
- if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
+ if ((par->video & PM3VideoControl_HSYNC_MASK) ==
PM3VideoControl_HSYNC_ACTIVE_HIGH)
tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
- if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
+ if ((par->video & PM3VideoControl_VSYNC_MASK) ==
PM3VideoControl_VSYNC_ACTIVE_HIGH)
tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
-
- PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
- DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
-
- if (flatpanel[l_fb_info->board_num])
- {
- PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
- PM3_WAIT(2);
- PM3_WRITE_REG(PM3VSConfiguration, 0x06);
- PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
- tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
- }
- else
- PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
- switch (l_fb_info->current_par->depth) {
+ PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
+ DPRINTK("PM3RD_SyncControl: %d\n", tempsync);
+
+ PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
+
+ switch (info->var.bits_per_pixel) {
case 8:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_8_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_CI8_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
break;
case 12:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_16_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_4444_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
- break;
+ break;
case 15:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_16_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_5551_FRONT_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
- break;
+ break;
case 16:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_16_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_565_FRONT_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
@@ -1239,1936 +377,280 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
break;
case 32:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_32_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_8888_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
break;
}
- PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc);
-
- PM3_SHOW_CUR_MODE;
+ PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc);
}
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
- struct pm3fb_par *curpar)
-{
- unsigned long pixsize1, pixsize2, clockused;
- unsigned long pre, feedback, post;
-
- DTRACE;
-
- clockused = PM3_READ_REG(PM3VClkCtl);
+/*
+ * hardware independent functions
+ */
+int pm3fb_init(void);
+int pm3fb_setup(char*);
- switch (clockused) {
- case 3:
- pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale);
- feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale);
- post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale);
+static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ u32 lpitch;
- DPRINTK(2,
- "DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
- pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
- feedback,
- post));
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ switch(var->bits_per_pixel) {
+ case 8:
+ var->red.length = var->green.length = var->blue.length = 8;
+ var->red.offset = var->green.offset = var->blue.offset = 0;
break;
- case 2:
- pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale);
- feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale);
- post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale);
-
- DPRINTK(2,
- "DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
- pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
- feedback,
- post));
+ case 12:
+ var->red.offset = 8;
+ var->red.length = 4;
+ var->green.offset = 4;
+ var->green.length = 4;
+ var->blue.offset = 0;
+ var->blue.length = 4;
+ var->transp.offset = 12;
+ var->transp.length = 4;
+ case 15:
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
break;
- case 1:
- pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale);
- feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale);
- post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale);
-
- DPRINTK(2,
- "DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
- pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
- feedback,
- post));
+ case 16:
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
break;
- case 0:
- pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale);
- feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale);
- post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale);
-
- DPRINTK(2,
- "DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
- pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
- feedback,
- post));
+ case 32:
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length = 8;
break;
default:
- pre = feedback = post = 0;
- DPRINTK(1, "Unknowk D clock used : %ld\n", clockused);
- break;
- }
-
- curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post);
-
- pixsize1 =
- PM3ByApertureMode_PIXELSIZE_MASK &
- (PM3_READ_REG(PM3ByAperture1Mode));
- pixsize2 =
- PM3ByApertureMode_PIXELSIZE_MASK &
- (PM3_READ_REG(PM3ByAperture2Mode));
-
- DASSERT((pixsize1 == pixsize2),
- "pixsize the same in both aperture\n");
-
- if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT)
- curpar->depth = 32;
- else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT)
- {
- curpar->depth = 16;
- }
- else
- curpar->depth = 8;
-
- /* not sure if I need to add one on the next ; it give better result with */
- curpar->htotal =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- 1 + PM3_READ_REG(PM3HTotal));
- curpar->hsend =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- PM3_READ_REG(PM3HsEnd));
- curpar->hsstart =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- PM3_READ_REG(PM3HsStart));
- curpar->hbend =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- PM3_READ_REG(PM3HbEnd));
-
- curpar->stride =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- PM3_READ_REG(PM3ScreenStride));
-
- curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal);
- curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd);
- curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart);
- curpar->vbend = PM3_READ_REG(PM3VbEnd);
-
- curpar->video = PM3_READ_REG(PM3VideoControl);
-
- curpar->base = PM3_READ_REG(PM3ScreenBase);
- curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */
- curpar->height = curpar->vtotal - curpar->vbend;
-
- DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n",
- curpar->width, curpar->height, curpar->pixclock,
- curpar->stride);
-}
-
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info)
-{
- unsigned long memsize = 0, tempBypass, i, temp1, temp2;
- u16 subvendor, subdevice;
- pm3fb_timing_result ptr;
-
- DTRACE;
-
- l_fb_info->fb_size = 64 * 1024 * 1024; /* pm3 aperture always 64 MB */
- pm3fb_mapIO(l_fb_info); /* temporary map IO */
-
- DASSERT((l_fb_info->vIOBase != NULL),
- "IO successfully mapped before mem detect\n");
- DASSERT((l_fb_info->v_fb != NULL),
- "FB successfully mapped before mem detect\n");
-
- /* card-specific stuff, *before* accessing *any* FB memory */
- if ((!pci_read_config_word
- (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
- &&
- (!pci_read_config_word
- (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
- i = 0; l_fb_info->board_type = 0;
- while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) {
- if ((cardbase[i].subvendor == subvendor) &&
- (cardbase[i].subdevice == subdevice) &&
- (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) {
- DPRINTK(2, "Card #%ld is an %s\n",
- l_fb_info->board_num,
- cardbase[i].cardname);
- if (cardbase[i].specific_setup)
- cardbase[i].specific_setup(l_fb_info);
- l_fb_info->board_type = i;
- }
- i++;
- }
- if (!l_fb_info->board_type) {
- DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n",
- l_fb_info->board_num, subvendor, subdevice);
- }
- } else {
- printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n",
- l_fb_info->board_num);
- }
-
- if (printtimings)
- pm3fb_show_cur_timing(l_fb_info);
-
- /* card-specific setup is done, we preserve the final
- memory timing for future reference */
- if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */
- return(0);
- }
-
- tempBypass = PM3_READ_REG(PM3MemBypassWriteMask);
-
- DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
-
- PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF);
-
- /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
- for (i = 0; i < 32; i++) {
- fb_writel(i * 0x00345678,
- (l_fb_info->v_fb + (i * 1048576)));
- mb();
- temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
-
- /* Let's check for wrapover, write will fail at 16MB boundary */
- if (temp1 == (i * 0x00345678))
- memsize = i;
- else
- break;
- }
-
- DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1);
-
- if (memsize == i) {
- for (i = 0; i < 32; i++) {
- /* Clear first 32MB ; 0 is 0, no need to byteswap */
- writel(0x0000000,
- (l_fb_info->v_fb + (i * 1048576)));
- mb();
- }
-
- for (i = 32; i < 64; i++) {
- fb_writel(i * 0x00345678,
- (l_fb_info->v_fb + (i * 1048576)));
- mb();
- temp1 =
- fb_readl((l_fb_info->v_fb + (i * 1048576)));
- temp2 =
- fb_readl((l_fb_info->v_fb +
- ((i - 32) * 1048576)));
- if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) /* different value, different RAM... */
- memsize = i;
- else
- break;
- }
- }
-
- DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1);
-
- PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass);
-
- pm3fb_unmapIO(l_fb_info);
- memsize = 1048576 * (memsize + 1);
-
- DPRINTK(2, "Returning 0x%08lx bytes\n", memsize);
-
- if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize))
- {
- printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]);
- memsize = 1048576 * forcesize[l_fb_info->board_num];
- }
-
- l_fb_info->fb_size = memsize;
-
- if (ptr == pm3fb_timing_retry)
- {
- printk(KERN_WARNING "pm3fb: retrying memory timings check");
- if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem)
- return(0);
- }
-
- return (memsize);
-}
-
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc)
-{
- int i;
-
- DTRACE;
-
- for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */
- {
- fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
+ DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+ return -EINVAL;
}
-}
-
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b)
-{
- int i;
-
- DTRACE;
-
- for (i = 0; i < 256 ; i++) /* fill color map with white */
- pm3fb_set_color(l_fb_info, i, r, g, b);
-
-}
-
-/* common initialisation */
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info)
-{
- DTRACE;
-
- DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num,
- (unsigned long) l_fb_info);
-
- strcpy(l_fb_info->gen.info.modename, permedia3_name);
- disp[l_fb_info->board_num].scrollmode = 0; /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */
- l_fb_info->gen.parsize = sizeof(struct pm3fb_par);
- l_fb_info->gen.info.changevar = NULL;
- l_fb_info->gen.info.fbops = &pm3fb_ops;
- l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]);
- if (fontn[l_fb_info->board_num][0])
- strcpy(l_fb_info->gen.info.fontname,
- fontn[l_fb_info->board_num]);
- l_fb_info->gen.info.switch_con = &fbgen_switch;
- l_fb_info->gen.info.updatevar = &fbgen_update_var; /* */
- l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
-
- pm3fb_mapIO(l_fb_info);
-
- pm3fb_clear_memory(l_fb_info, 0);
- pm3fb_clear_colormap(l_fb_info, 0, 0, 0);
-
- (void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1,
- &l_fb_info->gen.info);
+ var->height = var->width = -1;
- if (depth[l_fb_info->board_num]) /* override mode-defined depth */
- {
- pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]);
- (disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]);
+ if (var->xres != var->xres_virtual) {
+ DPRINTK("virtual x resolution != physical x resolution not supported\n");
+ return -EINVAL;
}
- (void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1,
- &l_fb_info->gen);
-
- fbgen_set_disp(-1, &l_fb_info->gen);
-
- do_install_cmap(0, &l_fb_info->gen.info);
-
- if (register_framebuffer(&l_fb_info->gen.info) < 0) {
- DPRINTK(1, "Couldn't register framebuffer\n");
- return;
+ if (var->yres > var->yres_virtual) {
+ DPRINTK("virtual y resolution < physical y resolution not possible\n");
+ return -EINVAL;
}
- PM3_WRITE_DAC_REG(PM3RD_CursorMode,
- PM3RD_CursorMode_CURSOR_DISABLE);
-
- PM3_SHOW_CUR_MODE;
-
- pm3fb_write_mode(l_fb_info);
-
- printk("fb%d: %s, using %uK of video memory (%s)\n",
- l_fb_info->gen.info.node,
- permedia3_name, (u32) (l_fb_info->fb_size >> 10),
- cardbase[l_fb_info->board_type].cardname);
-}
-
-/* **************************************************** */
-/* ***** accelerated permedia3-specific functions ***** */
-/* **************************************************** */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info)
-{
- DTRACE;
-
- PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
- PM3_SLOW_WRITE_REG(PM3Sync, 0);
- mb();
- do {
- while ((PM3_READ_REG(PM3OutFIFOWords)) == 0);
- rmb();
- } while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag);
-}
-
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info)
-{
- PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
- PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3StencilData, 0x0);
- PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FogMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3Window, 0x0);
-
- PM3_SLOW_WRITE_REG(PM3Config2D, 0x0);
-
- PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff);
-
- PM3_SLOW_WRITE_REG(PM3XBias, 0x0);
- PM3_SLOW_WRITE_REG(PM3YBias, 0x0);
- PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0);
-
- PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff);
-
- PM3_SLOW_WRITE_REG(PM3FBDestReadEnables,
- PM3FBDestReadEnables_E(0xff) |
- PM3FBDestReadEnables_R(0xff) |
- PM3FBDestReadEnables_ReferenceAlpha(0xff));
- PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0,
- PM3FBDestReadBufferWidth_Width(l_fb_info->
- current_par->
- width));
-
- PM3_SLOW_WRITE_REG(PM3FBDestReadMode,
- PM3FBDestReadMode_ReadEnable |
- PM3FBDestReadMode_Enable0);
- PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth,
- PM3FBSourceReadBufferWidth_Width(l_fb_info->
- current_par->
- width));
- PM3_SLOW_WRITE_REG(PM3FBSourceReadMode,
- PM3FBSourceReadMode_Blocking |
- PM3FBSourceReadMode_ReadEnable);
-
- {
- unsigned long rm = 1;
- switch (l_fb_info->current_par->depth) {
- case 8:
- PM3_SLOW_WRITE_REG(PM3PixelSize,
- PM3PixelSize_GLOBAL_8BIT);
- break;
- case 12:
- case 15:
- case 16:
- PM3_SLOW_WRITE_REG(PM3PixelSize,
- PM3PixelSize_GLOBAL_16BIT);
- break;
- case 32:
- PM3_SLOW_WRITE_REG(PM3PixelSize,
- PM3PixelSize_GLOBAL_32BIT);
- break;
- default:
- DPRINTK(1, "Unsupported depth %d\n",
- l_fb_info->current_par->depth);
- break;
- }
- PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm);
+ if (var->xoffset) {
+ DPRINTK("xoffset not supported\n");
+ return -EINVAL;
}
- PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff);
- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
- PM3_SLOW_WRITE_REG(PM3FBWriteMode,
- PM3FBWriteMode_WriteEnable |
- PM3FBWriteMode_OpaqueSpan |
- PM3FBWriteMode_Enable0);
- PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0,
- PM3FBWriteBufferWidth_Width(l_fb_info->
- current_par->
- width));
-
- PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0);
- {
- unsigned long sofb = (8UL * l_fb_info->fb_size) /
- ((depth2bpp(l_fb_info->current_par->depth))
- * l_fb_info->current_par->width); /* size in lines of FB */
- if (sofb > 4095)
- PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095);
- else
- PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb);
-
- switch (l_fb_info->current_par->depth) {
- case 8:
- PM3_SLOW_WRITE_REG(PM3DitherMode,
- (1 << 10) | (2 << 3));
- break;
- case 12:
- case 15:
- case 16:
- PM3_SLOW_WRITE_REG(PM3DitherMode,
- (1 << 10) | (1 << 3));
- break;
- case 32:
- PM3_SLOW_WRITE_REG(PM3DitherMode,
- (1 << 10) | (0 << 3));
- break;
- default:
- DPRINTK(1, "Unsupported depth %d\n",
- l_fb_info->current_par->depth);
- break;
- }
+ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ DPRINTK("interlace not supported\n");
+ return -EINVAL;
}
- PM3_SLOW_WRITE_REG(PM3dXDom, 0x0);
- PM3_SLOW_WRITE_REG(PM3dXSub, 0x0);
- PM3_SLOW_WRITE_REG(PM3dY, (1 << 16));
- PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0);
- PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0);
- PM3_SLOW_WRITE_REG(PM3StartY, 0x0);
- PM3_SLOW_WRITE_REG(PM3Count, 0x0);
-
-/* Disable LocalBuffer. better safe than sorry */
- PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0);
- PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0);
-
- pm3fb_wait_pm3(l_fb_info);
-}
+ var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
+ lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u32 c;
-
- DTRACE;
-
- sx = sx * fontwidth(p);
- width = width * fontwidth(p);
- sy = sy * fontheight(p);
- height = height * fontheight(p);
- c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
- /* block fills in 32bpp are hard, but in low res (width <= 1600 :-)
- we can use 16bpp operations, but not if NoWriteMask is on (SDRAM) */
- if ((l_fb_info->current_par->width > 1600) ||
- (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) {
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(width)) |
- (PM3Render2D_Height(height)));
- } else {
- PM3_WAIT(8);
-
- PM3_WRITE_REG(PM3FBBlockColor, c);
-
- PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT);
-
- PM3_WRITE_REG(PM3FBWriteBufferWidth0,
- PM3FBWriteBufferWidth_Width(l_fb_info->
- current_par->
- width << 1));
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx << 1)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- (PM3Render2D_Width(width << 1)) |
- (PM3Render2D_Height(height)));
-
- PM3_WRITE_REG(PM3FBWriteBufferWidth0,
- PM3FBWriteBufferWidth_Width(l_fb_info->
- current_par->
- width));
-
- PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT);
+ if (var->xres < 200 || var->xres > 2048) {
+ DPRINTK("width not supported: %u\n", var->xres);
+ return -EINVAL;
}
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- int sx, sy;
- u32 c;
-
- DTRACE;
-
- sx = conp->vc_cols * fontwidth(p); /* right margin */
- sy = conp->vc_rows * fontheight(p); /* bottom margin */
- c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
- if (!bottom_only) { /* right margin top->bottom */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset
- (p->var.xoffset +
- sx)) | (PM3RectanglePosition_YOffset(p->
- var.
- yoffset)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres - sx)) |
- (PM3Render2D_Height(p->var.yres)));
+ if (var->yres < 200 || var->yres > 4095) {
+ DPRINTK("height not supported: %u\n", var->yres);
+ return -EINVAL;
}
- /* bottom margin left -> right */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(p->var.xoffset)) |
- (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres)) |
- (PM3Render2D_Height(p->var.yres - sy)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u32 c;
-
- DTRACE;
-
- sx = sx * fontwidth(p);
- width = width * fontwidth(p);
- sy = sy * fontheight(p);
- height = height * fontheight(p);
- c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
- c = c | (c << 16);
-
- PM3_WAIT(4);
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3ForegroundColor, c);
- else
- PM3_WRITE_REG(PM3FBBlockColor, c);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(width)) |
- (PM3Render2D_Height(height)));
- else
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- (PM3Render2D_Width(width)) |
- (PM3Render2D_Height(height)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- int sx, sy;
- u32 c;
-
- DTRACE;
-
- sx = conp->vc_cols * fontwidth(p); /* right margin */
- sy = conp->vc_rows * fontheight(p); /* bottom margin */
- c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
- c = c | (c << 16);
-
- if (!bottom_only) { /* right margin top->bottom */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3ForegroundColor, c);
- else
- PM3_WRITE_REG(PM3FBBlockColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset
- (p->var.xoffset +
- sx)) | (PM3RectanglePosition_YOffset(p->
- var.
- yoffset)));
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres - sx)) |
- (PM3Render2D_Height(p->var.yres)));
- else
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- (PM3Render2D_Width(p->var.xres - sx)) |
- (PM3Render2D_Height(p->var.yres)));
+ if (lpitch * var->yres_virtual > info->fix.smem_len) {
+ DPRINTK("no memory for screen (%ux%ux%u)\n",
+ var->xres, var->yres_virtual, var->bits_per_pixel);
+ return -EINVAL;
}
-
- /* bottom margin left -> right */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3ForegroundColor, c);
- else
- PM3_WRITE_REG(PM3FBBlockColor, c);
-
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(p->var.xoffset)) |
- (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres)) |
- (PM3Render2D_Height(p->var.yres - sy)));
- else
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- (PM3Render2D_Width(p->var.xres)) |
- (PM3Render2D_Height(p->var.yres - sy)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u32 c;
-
- DTRACE;
-
- sx = sx * fontwidth(p);
- width = width * fontwidth(p);
- sy = sy * fontheight(p);
- height = height * fontheight(p);
-
- c = attr_bgcol_ec(p, conp);
- c |= c << 8;
- c |= c << 16;
-
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(width)) |
- (PM3Render2D_Height(height)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- int sx, sy;
- u32 c;
-
- DTRACE;
-
- sx = conp->vc_cols * fontwidth(p); /* right margin */
- sy = conp->vc_rows * fontheight(p); /* bottom margin */
- c = attr_bgcol_ec(p, conp);
- c |= c << 8;
- c |= c << 16;
-
- if (!bottom_only) { /* right margin top->bottom */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset
- (p->var.xoffset +
- sx)) | (PM3RectanglePosition_YOffset(p->
- var.
- yoffset)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres - sx)) |
- (PM3Render2D_Height(p->var.yres)));
+ if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
+ DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
+ return -EINVAL;
}
- /* bottom margin left -> right */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(p->var.xoffset)) |
- (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres)) |
- (PM3Render2D_Height(p->var.yres - sy)));
+ var->accel_flags = 0; /* Can't mmap if this is on */
- pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
- int sy, int sx,
- int dy, int dx, int height, int width)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- int x_align, o_x, o_y;
-
- DTRACE;
-
- sx = sx * fontwidth(p);
- dx = dx * fontwidth(p);
- width = width * fontwidth(p);
- sy = sy * fontheight(p);
- dy = dy * fontheight(p);
- height = height * fontheight(p);
-
- o_x = sx - dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */
- o_y = sy - dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */
-
- x_align = (sx & 0x1f);
-
- PM3_WAIT(6);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UserScissorEnable |
- PM3Config2D_ForegroundROPEnable |
- PM3Config2D_Blocking |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ScissorMinXY,
- ((dy & 0x0fff) << 16) | (dx & 0x0fff));
- PM3_WRITE_REG(PM3ScissorMaxXY,
- (((dy + height) & 0x0fff) << 16) |
- ((dx + width) & 0x0fff));
-
- PM3_WRITE_REG(PM3FBSourceReadBufferOffset,
- PM3FBSourceReadBufferOffset_XOffset(o_x) |
- PM3FBSourceReadBufferOffset_YOffset(o_y));
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(dx - x_align)) |
- (PM3RectanglePosition_YOffset(dy)));
-
- PM3_WRITE_REG(PM3Render2D,
- ((sx > dx) ? PM3Render2D_XPositive : 0) |
- ((sy > dy) ? PM3Render2D_YPositive : 0) |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- PM3Render2D_FBSourceReadEnable |
- (PM3Render2D_Width(width + x_align)) |
- (PM3Render2D_Height(height)));
-
- pm3fb_wait_pm3(l_fb_info);
+ DPRINTK("Checking graphics mode at %dx%d depth %d\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ return 0;
}
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
- int c, int yy, int xx)
+static int pm3fb_set_par(struct fb_info *info)
{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
- u32 fgx, bgx, ldat;
- int sx, sy, i;
+ struct pm3_par *par = info->par;
+ const u32 xres = (info->var.xres + 31) & ~31;
+ const int depth = (info->var.bits_per_pixel + 7) & ~7;
- DTRACE;
+ par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
+ (info->var.yoffset * xres)
+ + info->var.xoffset);
+ par->video = 0;
- if (l_fb_info->current_par->depth == 8)
- fgx = attr_fgcol(p, c);
- else if (depth2bpp(l_fb_info->current_par->depth) == 16)
- fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
+ if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
else
- fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
+ par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
- PM3_COLOR(fgx);
-
- if (l_fb_info->current_par->depth == 8)
- bgx = attr_bgcol(p, c);
- else if (depth2bpp(l_fb_info->current_par->depth) == 16)
- bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
+ if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
else
- bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
-
- PM3_COLOR(bgx);
-
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan);
-
- PM3_WRITE_REG(PM3ForegroundColor, fgx);
- PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
-
- /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
- /* and 16 bits for fontwidth <= 16 */
- /* same in _putcs, same for Y and fontheight */
- if (fontwidth(p) <= 8)
- asx = 2;
- else if (fontwidth(p) <= 16)
- asx = 3; /* look OK */
- if (fontheight(p) <= 8)
- asy = 2;
- else if (fontheight(p) <= 16)
- asy = 3; /* look OK */
- else if (fontheight(p) <= 32)
- asy = 4; /* look OK */
-
- sx = xx * fontwidth(p);
- sy = yy * fontheight(p);
-
- if (fontwidth(p) <= 8)
- o_x = (8 - (sx & 0x7)) & 0x7;
- else if (fontwidth(p) <= 16)
- o_x = (16 - (sx & 0xF)) & 0xF;
- if (fontheight(p) <= 8)
- o_y = (8 - (sy & 0x7)) & 0x7;
- else if (fontheight(p) <= 16)
- o_y = (16 - (sy & 0xF)) & 0xF;
- else if (fontheight(p) <= 32)
- o_y = (32 - (sy & 0x1F)) & 0x1F;
-
- PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
- (1 << 18) | /* BE */
- 1 | (asx << 1) | (asy << 4) | /* address select x/y */
- (1 << 20)); /* OpaqueSpan */
-
- if (fontwidth(p) <= 8) {
- cdat = p->fontdata + (c & p->charmask) * fontheight(p);
- } else {
- cdat =
- p->fontdata +
- ((c & p->charmask) * (fontheight(p) << 1));
- }
-
- PM3_WAIT(2 + fontheight(p));
-
- for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
- if (fontwidth(p) <= 8) {
- ldat = *cdat++;
- } else { /* assume fontwidth <= 16 ATM */
-
- ldat = ((*cdat++) << 8);
- ldat |= *cdat++;
- }
- PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
- }
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
+ par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_AreaStippleEnable |
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(fontwidth(p))) |
- (PM3Render2D_Height(fontheight(p))));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy,
- int xx)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
- u32 fgx, bgx, ldat;
- int sx, sy, i, j;
- u16 sc;
-
- DTRACE;
-
- sc = scr_readw(s);
- if (l_fb_info->current_par->depth == 8)
- fgx = attr_fgcol(p, sc);
- else if (depth2bpp(l_fb_info->current_par->depth) == 16)
- fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)];
- else
- fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)];
-
- PM3_COLOR(fgx);
-
- if (l_fb_info->current_par->depth == 8)
- bgx = attr_bgcol(p, sc);
- else if (depth2bpp(l_fb_info->current_par->depth) == 16)
- bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)];
+ if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+ par->video |= PM3VideoControl_LINE_DOUBLE_ON;
else
- bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)];
-
- PM3_COLOR(bgx);
-
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable |
- PM3Config2D_OpaqueSpan);
-
- PM3_WRITE_REG(PM3ForegroundColor, fgx);
- PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
-
- /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
- /* and 16 bits for fontwidth <= 16 */
- /* same in _putc, same for Y and fontheight */
- if (fontwidth(p) <= 8)
- asx = 2;
- else if (fontwidth(p) <= 16)
- asx = 3; /* look OK */
- if (fontheight(p) <= 8)
- asy = 2;
- else if (fontheight(p) <= 16)
- asy = 3; /* look OK */
- else if (fontheight(p) <= 32)
- asy = 4; /* look OK */
-
- sy = yy * fontheight(p);
-
- if (fontheight(p) <= 8)
- o_y = (8 - (sy & 0x7)) & 0x7;
- else if (fontheight(p) <= 16)
- o_y = (16 - (sy & 0xF)) & 0xF;
- else if (fontheight(p) <= 32)
- o_y = (32 - (sy & 0x1F)) & 0x1F;
-
- for (j = 0; j < count; j++) {
- sc = scr_readw(s + j);
- if (fontwidth(p) <= 8)
- cdat = p->fontdata +
- (sc & p->charmask) * fontheight(p);
- else
- cdat = p->fontdata +
- ((sc & p->charmask) * fontheight(p) << 1);
-
- sx = (xx + j) * fontwidth(p);
-
- if (fontwidth(p) <= 8)
- o_x = (8 - (sx & 0x7)) & 0x7;
- else if (fontwidth(p) <= 16)
- o_x = (16 - (sx & 0xF)) & 0xF;
-
- PM3_WAIT(3 + fontheight(p));
-
- PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
- (1 << 18) | /* BE */
- 1 | (asx << 1) | (asy << 4) | /* address select x/y */
- (1 << 20)); /* OpaqueSpan */
-
- for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
- if (fontwidth(p) <= 8) {
- ldat = *cdat++;
- } else { /* assume fontwidth <= 16 ATM */
- ldat = ((*cdat++) << 8);
- ldat |= *cdat++;
- }
- PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
- }
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_AreaStippleEnable |
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(fontwidth(p))) |
- (PM3Render2D_Height(fontheight(p))));
- }
- pm3fb_wait_pm3(l_fb_info);
-}
+ par->video |= PM3VideoControl_LINE_DOUBLE_OFF;
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-
- xx = xx * fontwidth(p);
- yy = yy * fontheight(p);
-
- if (l_fb_info->current_par->depth == 8)
- {
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F);
- else
- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
+ if (info->var.activate == FB_ACTIVATE_NOW)
+ par->video |= PM3VideoControl_ENABLE;
+ else {
+ par->video |= PM3VideoControl_DISABLE;
+ DPRINTK("PM3Video disabled\n");
}
-
- PM3_WAIT(3);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0xa)) | /* Oxa is GXinvert */
- PM3Config2D_FBDestReadEnable |
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(xx)) |
- (PM3RectanglePosition_YOffset(yy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(fontwidth(p))) |
- (PM3Render2D_Height(fontheight(p))));
-
- pm3fb_wait_pm3(l_fb_info);
-
- if (l_fb_info->current_par->depth == 8)
- {
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF);
- else
- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
- }
-}
-
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* *********************************** */
-/* ***** pre-init board(s) setup ***** */
-/* *********************************** */
-
-static void pm3fb_mode_setup(char *mode, unsigned long board_num)
-{
- struct pm3fb_info *l_fb_info = &(fb_info[board_num]);
- struct pm3fb_par *l_fb_par = &(current_par[board_num]);
- unsigned long i = 0;
-
- current_par_valid[board_num] = 0;
-
- if (!strncmp(mode, "current", 7)) {
- l_fb_info->use_current = 1; /* default w/ OpenFirmware */
- } else {
- while ((mode_base[i].name[0])
- && (!current_par_valid[board_num])) {
- if (!
- (strncmp
- (mode, mode_base[i].name,
- strlen(mode_base[i].name)))) {
- memcpy(l_fb_par, &(mode_base[i].user_mode),
- sizeof(struct pm3fb_par));
- current_par_valid[board_num] = 1;
- DPRINTK(2, "Mode set to %s\n",
- mode_base[i].name);
- }
- i++;
- }
- DASSERT(current_par_valid[board_num],
- "Valid mode on command line\n");
- }
-}
-
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num)
-{
- short l_bus = -1, l_slot = -1, l_func = -1;
- char *next;
-
- if (pciid) {
- l_bus = simple_strtoul(pciid, &next, 10);
- if (next && (next[0] == ':')) {
- pciid = next + 1;
- l_slot = simple_strtoul(pciid, &next, 10);
- if (next && (next[0] == ':')) {
- pciid = next + 1;
- l_func =
- simple_strtoul(pciid, (char **) NULL,
- 10);
- }
- }
- } else
- return;
-
- if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) {
- bus[board_num] = l_bus;
- slot[board_num] = l_slot;
- func[board_num] = l_func;
- DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n",
- board_num, l_bus, l_slot, l_func);
- } else {
- DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n",
- l_bus, l_slot, l_func, board_num);
- }
-}
-
-static void pm3fb_font_setup(char *lf, unsigned long board_num)
-{
- unsigned long lfs = strlen(lf);
-
- if (lfs > (PM3_FONTNAME_SIZE - 1)) {
- DPRINTK(1, "Fontname %s too long\n", lf);
- return;
- }
- strlcpy(fontn[board_num], lf, lfs + 1);
-}
-
-static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num)
-{
- unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
-
- if (!(depth_supported(bd))) {
- printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n",
- bds, board_num);
- return;
- }
- depth[board_num] = bd;
-}
-
-static void pm3fb_forcesize_setup(char *bds, unsigned long board_num)
-{
- unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
-
- if (bd > 64) {
- printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n",
- bds, board_num);
- return;
- }
- forcesize[board_num] = bd;
-}
-
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
-{
- char *next;
-
- if (!(isdigit(options[0]))) {
- (*bn) = 0;
- return (options);
- }
-
- (*bn) = simple_strtoul(options, &next, 10);
-
- if (next && (next[0] == ':') && ((*bn) >= 0)
- && ((*bn) <= PM3_MAX_BOARD)) {
- DPRINTK(2, "Board_num seen as %ld\n", (*bn));
- return (next + 1);
- } else {
- (*bn) = 0;
- DPRINTK(2, "Board_num default to %ld\n", (*bn));
- return (options);
- }
-}
-
-static void pm3fb_real_setup(char *options)
-{
- char *next;
- unsigned long i, bn;
- struct pm3fb_info *l_fb_info;
-
- DTRACE;
-
- DPRINTK(2, "Options : %s\n", options);
-
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- l_fb_info = &(fb_info[i]);
- memset(l_fb_info, 0, sizeof(struct pm3fb_info));
- l_fb_info->gen.fbhw = &pm3fb_switch;
- l_fb_info->board_num = i;
- current_par_valid[i] = 0;
- slot[i] = -1;
- func[i] = -1;
- bus[i] = -1;
- disable[i] = 0;
- noaccel[i] = 0;
- fontn[i][0] = '\0';
- depth[i] = 0;
- l_fb_info->current_par = &(current_par[i]);
- }
-
- /* eat up prefix pm3fb and whatever is used as separator i.e. :,= */
- if (!strncmp(options, "pm3fb", 5)) {
- options += 5;
- while (((*options) == ',') || ((*options) == ':')
- || ((*options) == '='))
- options++;
- }
-
- while (options) {
- bn = 0;
- if ((next = strchr(options, ','))) {
- (*next) = '\0';
- next++;
- }
-
- if (!strncmp(options, "mode:", 5)) {
- options = pm3fb_boardnum_setup(options + 5, &bn);
- DPRINTK(2, "Setting mode for board #%ld\n", bn);
- pm3fb_mode_setup(options, bn);
- } else if (!strncmp(options, "off:", 4)) {
- options = pm3fb_boardnum_setup(options + 4, &bn);
- DPRINTK(2, "Disabling board #%ld\n", bn);
- disable[bn] = 1;
- } else if (!strncmp(options, "off", 3)) { /* disable everything */
- for (i = 0; i < PM3_MAX_BOARD; i++)
- disable[i] = 1;
- } else if (!strncmp(options, "disable:", 8)) {
- options = pm3fb_boardnum_setup(options + 8, &bn);
- DPRINTK(2, "Disabling board #%ld\n", bn);
- disable[bn] = 1;
- } else if (!strncmp(options, "pciid:", 6)) {
- options = pm3fb_boardnum_setup(options + 6, &bn);
- DPRINTK(2, "Setting PciID for board #%ld\n", bn);
- pm3fb_pciid_setup(options, bn);
- } else if (!strncmp(options, "noaccel:", 8)) {
- options = pm3fb_boardnum_setup(options + 8, &bn);
- noaccel[bn] = 1;
- } else if (!strncmp(options, "font:", 5)) {
- options = pm3fb_boardnum_setup(options + 5, &bn);
- pm3fb_font_setup(options, bn);
- } else if (!strncmp(options, "depth:", 6)) {
- options = pm3fb_boardnum_setup(options + 6, &bn);
- pm3fb_bootdepth_setup(options, bn);
- } else if (!strncmp(options, "printtimings", 12)) {
- printtimings = 1;
- } else if (!strncmp(options, "flatpanel:", 10)) {
- options = pm3fb_boardnum_setup(options + 10, &bn);
- flatpanel[bn] = 1;
- } else if (!strncmp(options, "forcesize:", 10)) {
- options = pm3fb_boardnum_setup(options + 10, &bn);
- pm3fb_forcesize_setup(options, bn);
- }
- options = next;
- }
-}
-
-/* ********************************************** */
-/* ***** framebuffer API standard functions ***** */
-/* ********************************************** */
-
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
- const void *par, struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- struct pm3fb_par *p = (struct pm3fb_par *) par;
-
- DTRACE;
-
- strcpy(fix->id, permedia3_name);
- fix->smem_start = (unsigned long)l_fb_info->p_fb;
- fix->smem_len = l_fb_info->fb_size;
- fix->mmio_start = (unsigned long)l_fb_info->pIOBase;
- fix->mmio_len = PM3_REGS_SIZE;
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- fix->accel = FB_ACCEL_3DLABS_PERMEDIA3;
- else
-#endif /* PM3FB_USE_ACCEL */
- fix->accel = FB_ACCEL_NONE;
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->visual =
- (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- if (current_par_valid[l_fb_info->board_num])
- fix->line_length =
- l_fb_info->current_par->width *
- depth2ByPP(l_fb_info->current_par->depth);
- else
- fix->line_length = 0;
- fix->xpanstep = 64 / depth2bpp(p->depth);
- fix->ypanstep = 1;
- fix->ywrapstep = 0;
- return (0);
-}
-
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
- void *par, struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- struct pm3fb_par *p = (struct pm3fb_par *) par;
- struct pm3fb_par temp_p;
- u32 xres;
-
- DTRACE;
-
- DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
- DASSERT((p != NULL), "pm3fb_par* not NULL");
- DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL");
-
- memset(&temp_p, 0, sizeof(struct pm3fb_par));
- temp_p.width = (var->xres_virtual + 7) & ~7;
- temp_p.height = var->yres_virtual;
-
- if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */
- temp_p.depth = depth2bpp(var->bits_per_pixel);
- else
- temp_p.depth = var->bits_per_pixel;
-
- temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */
- temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */
-
- if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5))
- temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */
-
- if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4))
- temp_p.depth = 12; /* RGBA 4444 is stored as depth 12 */
-
-
- DPRINTK(2,
- "xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n",
- var->xres, var->yres, var->xres_virtual, var->yres_virtual,
- var->xoffset, var->yoffset);
-
- xres = (var->xres + 31) & ~31;
- if (temp_p.width < xres + var->xoffset)
- temp_p.width = xres + var->xoffset;
- if (temp_p.height < var->yres + var->yoffset)
- temp_p.height = var->yres + var->yoffset;
-
- if (temp_p.width > 2048) {
- DPRINTK(1, "virtual width not supported: %u\n",
- temp_p.width);
- return (-EINVAL);
- }
- if (var->yres < 200) {
- DPRINTK(1, "height not supported: %u\n", (u32) var->yres);
- return (-EINVAL);
- }
- if (temp_p.height < 200 || temp_p.height > 4095) {
- DPRINTK(1, "virtual height not supported: %u\n",
- temp_p.height);
- return (-EINVAL);
- }
- if (!(depth_supported(temp_p.depth))) {
- DPRINTK(1, "depth not supported: %u\n", temp_p.depth);
- return (-EINVAL);
- }
- if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) >
- l_fb_info->fb_size) {
- DPRINTK(1, "no memory for screen (%ux%ux%u)\n",
- temp_p.width, temp_p.height, temp_p.depth);
- return (-EINVAL);
- }
-
- if ((!var->pixclock) ||
- (!var->right_margin) ||
- (!var->hsync_len) ||
- (!var->left_margin) ||
- (!var->lower_margin) ||
- (!var->vsync_len) || (!var->upper_margin)
- ) {
- unsigned long i = 0, done = 0;
- printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n");
-
- while ((mode_base[i].user_mode.width) && !done) {
- if ((mode_base[i].user_mode.width == temp_p.width)
- && (mode_base[i].user_mode.height ==
- temp_p.height)) {
- printk(KERN_NOTICE "pm3fb: using close match %s\n",
- mode_base[i].name);
- temp_p = mode_base[i].user_mode;
- done = 1;
- }
- i++;
- }
- if (!done)
- return (-EINVAL);
- } else {
- temp_p.pixclock = PICOS2KHZ(var->pixclock);
- if (temp_p.pixclock > PM3_MAX_PIXCLOCK) {
- DPRINTK(1, "pixclock too high (%uKHz)\n",
- temp_p.pixclock);
- return (-EINVAL);
- }
-
- temp_p.hsstart = var->right_margin;
- temp_p.hsend = var->right_margin + var->hsync_len;
- temp_p.hbend =
- var->right_margin + var->hsync_len + var->left_margin;
- temp_p.htotal = xres + temp_p.hbend;
-
- temp_p.vsstart = var->lower_margin;
- temp_p.vsend = var->lower_margin + var->vsync_len;
- temp_p.vbend =
- var->lower_margin + var->vsync_len + var->upper_margin;
- temp_p.vtotal = var->yres + temp_p.vbend;
-
- temp_p.stride = temp_p.width;
-
- DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n",
- temp_p.width, temp_p.height, temp_p.pixclock,
- temp_p.stride);
-
- temp_p.base =
- pm3fb_Shiftbpp(l_fb_info, temp_p.depth,
- (var->yoffset * xres) + var->xoffset);
-
- temp_p.video = 0;
-
- if (var->sync & FB_SYNC_HOR_HIGH_ACT)
- temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
- else
- temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
-
- if (var->sync & FB_SYNC_VERT_HIGH_ACT)
- temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
- else
- temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
-
- if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
- DPRINTK(1, "Interlaced mode not supported\n\n");
- return (-EINVAL);
- }
-
- if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
- temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON;
- else
- temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF;
-
- if (var->activate == FB_ACTIVATE_NOW)
- temp_p.video |= PM3VideoControl_ENABLE;
- else {
- temp_p.video |= PM3VideoControl_DISABLE;
- DPRINTK(2, "PM3Video disabled\n");
- }
-
- switch (temp_p.depth) {
- case 8:
- temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT;
- break;
- case 12:
- case 15:
- case 16:
- temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT;
- break;
- case 32:
- temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT;
- break;
- default:
- DPRINTK(1, "Unsupported depth\n");
- break;
- }
- }
- (*p) = temp_p;
-
-#ifdef PM3FB_USE_ACCEL
- if (var->accel_flags & FB_ACCELF_TEXT)
- noaccel[l_fb_info->board_num] = 0;
- else
- noaccel[l_fb_info->board_num] = 1;
-#endif /* PM3FB_USE_ACCEL */
-
- return (0);
-}
-
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d)
-{
- switch (d) {
+ switch (depth) {
case 8:
- var->red.length = var->green.length = var->blue.length = 8;
- var->red.offset = var->green.offset = var->blue.offset = 0;
- var->transp.offset = var->transp.length = 0;
+ par->video |= PM3VideoControl_PIXELSIZE_8BIT;
break;
-
case 12:
- var->red.offset = 8;
- var->red.length = 4;
- var->green.offset = 4;
- var->green.length = 4;
- var->blue.offset = 0;
- var->blue.length = 4;
- var->transp.offset = 12;
- var->transp.length = 4;
- break;
-
case 15:
- var->red.offset = 10;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 5;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 15;
- var->transp.length = 1;
- break;
-
case 16:
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = var->transp.length = 0;
+ par->video |= PM3VideoControl_PIXELSIZE_16BIT;
break;
-
case 32:
- var->transp.offset = 24;
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = var->green.length =
- var->blue.length = var->transp.length = 8;
+ par->video |= PM3VideoControl_PIXELSIZE_32BIT;
break;
-
default:
- DPRINTK(1, "Unsupported depth %ld\n", d);
+ DPRINTK("Unsupported depth\n");
break;
}
-}
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
- const void *par, struct fb_info_gen *info)
-{
- struct pm3fb_par *p = (struct pm3fb_par *) par;
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- u32 base;
-
- DTRACE;
-
- DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
- DASSERT((p != NULL), "pm3fb_par* not NULL");
- DASSERT((info != NULL), "fb_info_gen* not NULL");
-
- memset(var, 0, sizeof(struct fb_var_screeninfo));
-
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- var->accel_flags |= FB_ACCELF_TEXT;
-#endif /* PM3FB_USE_ACCEL */
-
- var->xres_virtual = p->width;
- var->yres_virtual = p->height;
- var->xres = p->htotal - p->hbend;
- var->yres = p->vtotal - p->vbend;
-
- DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres);
-
- var->right_margin = p->hsstart;
- var->hsync_len = p->hsend - p->hsstart;
- var->left_margin = p->hbend - p->hsend;
- var->lower_margin = p->vsstart;
- var->vsync_len = p->vsend - p->vsstart;
- var->upper_margin = p->vbend - p->vsend;
- var->bits_per_pixel = depth2bpp(p->depth);
-
- pm3fb_encode_depth(var, p->depth);
-
- base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base);
-
- var->xoffset = base % var->xres;
- var->yoffset = base / var->xres;
-
- var->height = var->width = -1;
-
- var->pixclock = KHZ2PICOS(p->pixclock);
-
- if ((p->video & PM3VideoControl_HSYNC_MASK) ==
- PM3VideoControl_HSYNC_ACTIVE_HIGH)
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
- if ((p->video & PM3VideoControl_VSYNC_MASK) ==
- PM3VideoControl_VSYNC_ACTIVE_HIGH)
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
- if (p->video & PM3VideoControl_LINE_DOUBLE_ON)
- var->vmode = FB_VMODE_DOUBLE;
-
- return (0);
-}
-
-static void pm3fb_get_par(void *par, struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- DTRACE;
+ info->fix.visual =
+ (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ info->fix.line_length = ((info->var.xres_virtual + 7) & ~7)
+ * depth / 8;
- if (!current_par_valid[l_fb_info->board_num]) {
- if (l_fb_info->use_current)
- pm3fb_read_mode(l_fb_info, l_fb_info->current_par);
- else
- memcpy(l_fb_info->current_par,
- &(mode_base[0].user_mode),
- sizeof(struct pm3fb_par));
- current_par_valid[l_fb_info->board_num] = 1;
- }
- *((struct pm3fb_par *) par) = *(l_fb_info->current_par);
-}
-
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- DTRACE;
-
- *(l_fb_info->current_par) = *((struct pm3fb_par *) par);
- current_par_valid[l_fb_info->board_num] = 1;
-
- pm3fb_write_mode(l_fb_info);
-
-#ifdef PM3FB_USE_ACCEL
- pm3fb_init_engine(l_fb_info);
-#endif /* PM3FB_USE_ACCEL */
-}
-
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
- unsigned char regno, unsigned char r,
- unsigned char g, unsigned char b)
-{
- DTRACE;
-
- PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno);
- PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r);
- PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g);
- PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b);
-}
-
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- DTRACE;
-
- if (regno < 256) {
- *red =
- l_fb_info->palette[regno].red << 8 | l_fb_info->
- palette[regno].red;
- *green =
- l_fb_info->palette[regno].green << 8 | l_fb_info->
- palette[regno].green;
- *blue =
- l_fb_info->palette[regno].blue << 8 | l_fb_info->
- palette[regno].blue;
- *transp =
- l_fb_info->palette[regno].transp << 8 | l_fb_info->
- palette[regno].transp;
- }
- return (regno > 255);
+/* pm3fb_clear_memory(info, 0);*/
+ pm3fb_clear_colormap(par, 0, 0, 0);
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorMode,
+ PM3RD_CursorMode_CURSOR_DISABLE);
+ pm3fb_write_mode(info);
+ return 0;
}
static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- DTRACE;
+ struct pm3_par *par = info->par;
+
+ if (regno >= 256) /* no. of hw registers */
+ return -EINVAL;
+
+ /* grayscale works only partially under directcolor */
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ /* Directcolor:
+ * var->{color}.offset contains start of bitfield
+ * var->{color}.length contains length of bitfield
+ * {hardwarespecific} contains width of DAC
+ * pseudo_palette[X] is programmed to (X << red.offset) |
+ * (X << green.offset) |
+ * (X << blue.offset)
+ * RAMDAC[X] is programmed to (red, green, blue)
+ * color depth = SUM(var->{color}.length)
+ *
+ * Pseudocolor:
+ * var->{color}.offset is 0
+ * var->{color}.length contains width of DAC or the number of unique
+ * colors available (color depth)
+ * pseudo_palette is not used
+ * RAMDAC[X] is programmed to (red, green, blue)
+ * color depth = var->{color}.length
+ */
- if (regno < 16) {
- switch (l_fb_info->current_par->depth) {
-#ifdef FBCON_HAS_CFB8
+ /*
+ * This is the point where the color is converted to something that
+ * is acceptable by the hardware.
+ */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+#undef CNVT_TOHW
+
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ u32 v;
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ switch (info->var.bits_per_pixel) {
case 8:
break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 12:
- l_fb_info->cmap.cmap12[regno] =
- (((u32) red & 0xf000) >> 4) |
- (((u32) green & 0xf000) >> 8) |
- (((u32) blue & 0xf000) >> 12);
- break;
-
- case 15:
- l_fb_info->cmap.cmap15[regno] =
- (((u32) red & 0xf800) >> 1) |
- (((u32) green & 0xf800) >> 6) |
- (((u32) blue & 0xf800) >> 11);
- break;
-
case 16:
- l_fb_info->cmap.cmap16[regno] =
- ((u32) red & 0xf800) |
- (((u32) green & 0xfc00) >> 5) |
- (((u32) blue & 0xf800) >> 11);
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
+ case 24:
case 32:
- l_fb_info->cmap.cmap32[regno] =
- (((u32) transp & 0xff00) << 16) |
- (((u32) red & 0xff00) << 8) |
- (((u32) green & 0xff00)) |
- (((u32) blue & 0xff00) >> 8);
- break;
-#endif
- default:
- DPRINTK(1, "bad depth %u\n",
- l_fb_info->current_par->depth);
+ ((u32*)(info->pseudo_palette))[regno] = v;
break;
}
+ return 0;
}
- if (regno < 256) {
- l_fb_info->palette[regno].red = red >> 8;
- l_fb_info->palette[regno].green = green >> 8;
- l_fb_info->palette[regno].blue = blue >> 8;
- l_fb_info->palette[regno].transp = transp >> 8;
- if (l_fb_info->current_par->depth == 8)
- pm3fb_set_color(l_fb_info, regno, red >> 8,
- green >> 8, blue >> 8);
- }
- return (regno > 255);
+ else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+ pm3fb_set_color(par, regno, red, green, blue);
+
+ return 0;
}
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info)
+static int pm3fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- u32 video;
-
- DTRACE;
+ struct pm3_par *par = info->par;
+ const u32 xres = (var->xres + 31) & ~31;
- if (!current_par_valid[l_fb_info->board_num])
- return (1);
+ par->base = pm3fb_shift_bpp(var->bits_per_pixel,
+ (var->yoffset * xres)
+ + var->xoffset);
+ PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+ return 0;
+}
- video = l_fb_info->current_par->video;
+static int pm3fb_blank(int blank_mode, struct fb_info *info)
+{
+ struct pm3_par *par = info->par;
+ u32 video = par->video;
/*
* Oxygen VX1 - it appears that setting PM3VideoControl and
@@ -3181,454 +663,345 @@ static int pm3fb_blank(int blank_mode, struct fb_info_gen *info)
video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
PM3VideoControl_VSYNC_ACTIVE_HIGH;
- if (blank_mode > 0) {
- switch (blank_mode - 1) {
-
- case VESA_NO_BLANKING: /* FIXME */
- video = video & ~(PM3VideoControl_ENABLE);
- break;
-
- case VESA_HSYNC_SUSPEND:
- video = video & ~(PM3VideoControl_HSYNC_MASK |
- PM3VideoControl_BLANK_ACTIVE_LOW);
- break;
- case VESA_VSYNC_SUSPEND:
- video = video & ~(PM3VideoControl_VSYNC_MASK |
- PM3VideoControl_BLANK_ACTIVE_LOW);
- break;
- case VESA_POWERDOWN:
- video = video & ~(PM3VideoControl_HSYNC_MASK |
- PM3VideoControl_VSYNC_MASK |
- PM3VideoControl_BLANK_ACTIVE_LOW);
- break;
- default:
- DPRINTK(1, "Unsupported blanking %d\n",
- blank_mode);
- return (1);
- break;
- }
- }
-
- PM3_SLOW_WRITE_REG(PM3VideoControl, video);
-
- return (0);
-}
-
-static void pm3fb_set_disp(const void *par, struct display *disp,
- struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- struct pm3fb_par *p = (struct pm3fb_par *) par;
- u32 flags;
-
- DTRACE;
-
- local_irq_save(flags);
- info->info.screen_base = l_fb_info->v_fb;
- switch (p->depth) {
-#ifdef FBCON_HAS_CFB8
- case 8:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb8;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb8;
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ video = video | PM3VideoControl_ENABLE;
break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 12:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb16;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb16;
- disp->dispsw_data = l_fb_info->cmap.cmap12;
+ case FB_BLANK_NORMAL: /* FIXME */
+ video = video & ~(PM3VideoControl_ENABLE);
break;
- case 15:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb16;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb16;
- disp->dispsw_data = l_fb_info->cmap.cmap15;
+ case FB_BLANK_HSYNC_SUSPEND:
+ video = video & ~(PM3VideoControl_HSYNC_MASK |
+ PM3VideoControl_BLANK_ACTIVE_LOW);
break;
- case 16:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb16;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb16;
- disp->dispsw_data = l_fb_info->cmap.cmap16;
+ case FB_BLANK_VSYNC_SUSPEND:
+ video = video & ~(PM3VideoControl_VSYNC_MASK |
+ PM3VideoControl_BLANK_ACTIVE_LOW);
break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb32;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb32;
- disp->dispsw_data = l_fb_info->cmap.cmap32;
+ case FB_BLANK_POWERDOWN:
+ video = video & ~(PM3VideoControl_HSYNC_MASK |
+ PM3VideoControl_VSYNC_MASK |
+ PM3VideoControl_BLANK_ACTIVE_LOW);
break;
-#endif /* FBCON_HAS_CFB32 */
default:
- disp->dispsw = &fbcon_dummy;
- DPRINTK(1, "Invalid depth, using fbcon_dummy\n");
- break;
+ DPRINTK("Unsupported blanking %d\n", blank_mode);
+ return 1;
}
- local_irq_restore(flags);
+
+ PM3_SLOW_WRITE_REG(par,PM3VideoControl, video);
+
+ return 0;
}
-/* */
-static void pm3fb_detect(void)
-{
- struct pci_dev *dev_array[PM3_MAX_BOARD];
- struct pci_dev *dev = NULL;
- struct pm3fb_info *l_fb_info = &(fb_info[0]);
- unsigned long i, j, done;
+ /*
+ * Frame buffer operations
+ */
- DTRACE;
+static struct fb_ops pm3fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = pm3fb_check_var,
+ .fb_set_par = pm3fb_set_par,
+ .fb_setcolreg = pm3fb_setcolreg,
+ .fb_pan_display = pm3fb_pan_display,
+ .fb_fillrect = cfb_fillrect, /* Needed !!! */
+ .fb_copyarea = cfb_copyarea, /* Needed !!! */
+ .fb_imageblit = cfb_imageblit, /* Needed !!! */
+ .fb_blank = pm3fb_blank,
+};
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- dev_array[i] = NULL;
- fb_info[i].dev = NULL;
- }
+/* ------------------------------------------------------------------------- */
- dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
- PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
+ /*
+ * Initialization
+ */
- for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) {
- dev_array[i] = dev;
- dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
- PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
- }
+/* mmio register are already mapped when this function is called */
+/* the pm3fb_fix.smem_start is also set */
+static unsigned long pm3fb_size_memory(struct pm3_par *par)
+{
+ unsigned long memsize = 0, tempBypass, i, temp1, temp2;
+ unsigned char __iomem *screen_mem;
- if (dev) { /* more than PM3_MAX_BOARD */
- printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n",
- PM3_MAX_BOARD);
+ pm3fb_fix.smem_len = 64 * 1024 * 1024; /* request full aperture size */
+ /* Linear frame buffer - request region and map it. */
+ if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
+ "pm3fb smem")) {
+ printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
+ return 0;
}
-
- if (!dev_array[0]) { /* not a single board, abort */
- return;
+ screen_mem =
+ ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ if (!screen_mem) {
+ printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
+ release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ return 0;
}
- /* allocate user-defined boards */
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) {
- for (j = 0; j < PM3_MAX_BOARD; j++) {
- if ((dev_array[j] != NULL) &&
- (dev_array[j]->bus->number == bus[i])
- && (PCI_SLOT(dev_array[j]->devfn) ==
- slot[i])
- && (PCI_FUNC(dev_array[j]->devfn) ==
- func[i])) {
- fb_info[i].dev = dev_array[j];
- dev_array[j] = NULL;
- }
- }
- }
+ /* TODO: card-specific stuff, *before* accessing *any* FB memory */
+ /* For Appian Jeronimo 2000 board second head */
+
+ tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);
+
+ DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
+
+ PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
+
+ /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
+ for (i = 0; i < 32; i++) {
+ fb_writel(i * 0x00345678,
+ (screen_mem + (i * 1048576)));
+ mb();
+ temp1 = fb_readl((screen_mem + (i * 1048576)));
+
+ /* Let's check for wrapover, write will fail at 16MB boundary */
+ if (temp1 == (i * 0x00345678))
+ memsize = i;
+ else
+ break;
}
- /* allocate remaining boards */
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- if (fb_info[i].dev == NULL) {
- done = 0;
- for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) {
- if (dev_array[j] != NULL) {
- fb_info[i].dev = dev_array[j];
- dev_array[j] = NULL;
- done = 1;
- }
- }
+
+ DPRINTK("First detect pass already got %ld MB\n", memsize + 1);
+
+ if (memsize + 1 == i) {
+ for (i = 0; i < 32; i++) {
+ /* Clear first 32MB ; 0 is 0, no need to byteswap */
+ writel(0x0000000,
+ (screen_mem + (i * 1048576)));
+ mb();
}
- }
- /* at that point, all PCI Permedia3 are detected and allocated */
- /* now, initialize... or not */
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- l_fb_info = &(fb_info[i]);
- if (l_fb_info->dev && !disable[i]) { /* PCI device was found and not disabled by user */
- DPRINTK(2,
- "found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
- (unsigned long) l_fb_info->dev,
- (unsigned long) l_fb_info->dev->vendor,
- (unsigned long) l_fb_info->dev->device,
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 0),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 1),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 2),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 3),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 4),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 5),
- (unsigned long) l_fb_info->dev->irq);
-
- l_fb_info->pIOBase =
- (unsigned char *)
- pci_resource_start(l_fb_info->dev, 0);
-#ifdef __BIG_ENDIAN
- l_fb_info->pIOBase += PM3_REGS_SIZE;
-#endif
- l_fb_info->vIOBase = (unsigned char *) -1;
- l_fb_info->p_fb =
- (unsigned char *)
- pci_resource_start(l_fb_info->dev, 1);
- l_fb_info->v_fb = (unsigned char *) -1;
-
- if (!request_mem_region
- ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
- "pm3fb")) {
- printk
- (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
- l_fb_info->board_num);
- continue;
- }
- if (!request_mem_region
- ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
- "pm3fb I/O regs")) {
- printk
- (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
- l_fb_info->board_num);
- continue;
- }
- if (forcesize[l_fb_info->board_num])
- l_fb_info->fb_size = forcesize[l_fb_info->board_num];
-
- l_fb_info->fb_size =
- pm3fb_size_memory(l_fb_info);
- if (l_fb_info->fb_size) {
- (void) pci_enable_device(l_fb_info->dev);
- pm3fb_common_init(l_fb_info);
- } else
- printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
+ for (i = 32; i < 64; i++) {
+ fb_writel(i * 0x00345678,
+ (screen_mem + (i * 1048576)));
+ mb();
+ temp1 =
+ fb_readl((screen_mem + (i * 1048576)));
+ temp2 =
+ fb_readl((screen_mem + ((i - 32) * 1048576)));
+ /* different value, different RAM... */
+ if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
+ memsize = i;
+ else
+ break;
}
}
-}
+ DPRINTK("Second detect pass got %ld MB\n", memsize + 1);
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
- struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+ PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);
- DTRACE;
+ iounmap(screen_mem);
+ release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ memsize = 1048576 * (memsize + 1);
- if (!current_par_valid[l_fb_info->board_num])
- return -EINVAL;
+ DPRINTK("Returning 0x%08lx bytes\n", memsize);
- l_fb_info->current_par->base = /* in 128 bits chunk - i.e. AFTER Shiftbpp */
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- (var->yoffset * l_fb_info->current_par->width) +
- var->xoffset);
- PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
- return 0;
+ return memsize;
}
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
+static int __devinit pm3fb_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- u32 cm, i;
-#ifdef PM3FB_MASTER_DEBUG
- char cc[3];
-#endif /* PM3FB_MASTER_DEBUG */
+ struct fb_info *info;
+ struct pm3_par *par;
+ struct device* device = &dev->dev; /* for pci drivers */
+ int err, retval = -ENXIO;
- switch(cmd)
- {
-#ifdef PM3FB_MASTER_DEBUG
- case PM3FBIO_CLEARMEMORY:
- if (copy_from_user(&cm, (void *)arg, sizeof(u32)))
- return(-EFAULT);
- pm3fb_clear_memory(l_fb_info, cm);
- return(0);
- break;
+ err = pci_enable_device(dev);
+ if (err) {
+ printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err);
+ return err;
+ }
+ /*
+ * Dynamically allocate info and par
+ */
+ info = framebuffer_alloc(sizeof(struct pm3_par), device);
- case PM3FBIO_CLEARCMAP:
- if (copy_from_user(cc, (void*)arg, 3 * sizeof(char)))
- return(-EFAULT);
- pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]);
- return(0);
- break;
-#endif /* PM3FB_MASTER_DEBUG */
-
- case PM3FBIO_RESETCHIP:
- cm = 1;
- PM3_SLOW_WRITE_REG(PM3ResetStatus, 1);
- for (i = 0 ; (i < 10000) && cm ; i++)
- {
- PM3_DELAY(10);
- cm = PM3_READ_REG(PM3ResetStatus);
- }
- if (cm)
- {
- printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm);
- return(-EIO);
- }
- /* first thing first, reload memory timings */
- pm3fb_write_memory_timings(l_fb_info);
-#ifdef PM3FB_USE_ACCEL
- pm3fb_init_engine(l_fb_info);
-#endif /* PM3FB_USE_ACCEL */
- pm3fb_write_mode(l_fb_info);
- return(0);
- break;
+ if (!info)
+ return -ENOMEM;
+ par = info->par;
- default:
- DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd);
- return(-EINVAL);
+ /*
+ * Here we set the screen_base to the virtual memory address
+ * for the framebuffer.
+ */
+ pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
+ pm3fb_fix.mmio_len = PM3_REGS_SIZE;
+
+ /* Registers - request region and map it. */
+ if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
+ "pm3fb regbase")) {
+ printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n");
+ goto err_exit_neither;
+ }
+ par->v_regs =
+ ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+ if (!par->v_regs) {
+ printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",
+ pm3fb_fix.id);
+ release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+ goto err_exit_neither;
+ }
+
+#if defined(__BIG_ENDIAN)
+ pm3fb_fix.mmio_start += PM3_REGS_SIZE;
+ DPRINTK("Adjusting register base for big-endian.\n");
+#endif
+ /* Linear frame buffer - request region and map it. */
+ pm3fb_fix.smem_start = pci_resource_start(dev, 1);
+ pm3fb_fix.smem_len = pm3fb_size_memory(par);
+ if (!pm3fb_fix.smem_len)
+ {
+ printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");
+ goto err_exit_mmio;
}
-}
-
-/* ****************************************** */
-/* ***** standard FB API init functions ***** */
-/* ****************************************** */
+ if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
+ "pm3fb smem")) {
+ printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
+ goto err_exit_mmio;
+ }
+ info->screen_base =
+ ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ if (!info->screen_base) {
+ printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
+ release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ goto err_exit_mmio;
+ }
+ info->screen_size = pm3fb_fix.smem_len;
-int __init pm3fb_setup(char *options)
-{
- long opsi = strlen(options);
+ info->fbops = &pm3fb_ops;
- DTRACE;
+ par->video = PM3_READ_REG(par, PM3VideoControl);
- memcpy(g_options, options,
- ((opsi + 1) >
- PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
- g_options[PM3_OPTIONS_SIZE - 1] = 0;
+ info->fix = pm3fb_fix;
+ info->pseudo_palette = par->palette;
+ info->flags = FBINFO_DEFAULT;/* | FBINFO_HWACCEL_YPAN;*/
- return (0);
-}
+ /*
+ * This should give a reasonable default video mode. The following is
+ * done when we can set a video mode.
+ */
+ if (!mode_option)
+ mode_option = "640x480@60";
-int __init pm3fb_init(void)
-{
- DTRACE;
+ retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
- DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $");
+ if (!retval || retval == 4) {
+ retval = -EINVAL;
+ goto err_exit_both;
+ }
- pm3fb_real_setup(g_options);
+ /* This has to been done !!! */
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ retval = -ENOMEM;
+ goto err_exit_both;
+ }
- pm3fb_detect();
+ /*
+ * For drivers that can...
+ */
+ pm3fb_check_var(&info->var, info);
- if (!fb_info[0].dev) { /* not even one board ??? */
- DPRINTK(1, "No PCI Permedia3 board detected\n");
+ if (register_framebuffer(info) < 0) {
+ retval = -EINVAL;
+ goto err_exit_all;
}
- return (0);
+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+ info->fix.id);
+ pci_set_drvdata(dev, info); /* or dev_set_drvdata(device, info) */
+ return 0;
+
+ err_exit_all:
+ fb_dealloc_cmap(&info->cmap);
+ err_exit_both:
+ iounmap(info->screen_base);
+ release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ err_exit_mmio:
+ iounmap(par->v_regs);
+ release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+ err_exit_neither:
+ framebuffer_release(info);
+ return retval;
}
-/* ************************* */
-/* **** Module support ***** */
-/* ************************* */
+ /*
+ * Cleanup
+ */
+static void __devexit pm3fb_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
-#ifdef MODULE
-MODULE_AUTHOR("Romain Dolbeau");
-MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
-static char *mode[PM3_MAX_BOARD];
-module_param_array(mode, charp, NULL, 0);
-MODULE_PARM_DESC(mode,"video mode");
-module_param_array(disable, short, NULL, 0);
-MODULE_PARM_DESC(disable,"disable board");
-static short off[PM3_MAX_BOARD];
-module_param_array(off, short, NULL, 0);
-MODULE_PARM_DESC(off,"disable board");
-static char *pciid[PM3_MAX_BOARD];
-module_param_array(pciid, charp, NULL, 0);
-MODULE_PARM_DESC(pciid,"board PCI Id");
-module_param_array(noaccel, short, NULL, 0);
-MODULE_PARM_DESC(noaccel,"disable accel");
-static char *font[PM3_MAX_BOARD];
-module_param_array(font, charp, NULL, 0);
-MODULE_PARM_DESC(font,"choose font");
-module_param(depth, short, NULL, 0);
-MODULE_PARM_DESC(depth,"boot-time depth");
-module_param(printtimings, short, NULL, 0);
-MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
-module_param(forcesize, short, NULL, 0);
-MODULE_PARM_DESC(forcesize, "force specified memory size");
-/*
-MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
-MODULE_GENERIC_TABLE(gtype,name)
-MODULE_DEVICE_TABLE(type,name)
-*/
+ if (info) {
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct pm3_par *par = info->par;
-void pm3fb_build_options(void)
-{
- int i;
- char ts[128];
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
- strcpy(g_options, "pm3fb");
- for (i = 0; i < PM3_MAX_BOARD ; i++)
- {
- if (mode[i])
- {
- sprintf(ts, ",mode:%d:%s", i, mode[i]);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (disable[i] || off[i])
- {
- sprintf(ts, ",disable:%d:", i);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (pciid[i])
- {
- sprintf(ts, ",pciid:%d:%s", i, pciid[i]);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (noaccel[i])
- {
- sprintf(ts, ",noaccel:%d:", i);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (font[i])
- {
- sprintf(ts, ",font:%d:%s", i, font[i]);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (depth[i])
- {
- sprintf(ts, ",depth:%d:%d", i, depth[i]);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
+ iounmap(info->screen_base);
+ release_mem_region(fix->smem_start, fix->smem_len);
+ iounmap(par->v_regs);
+ release_mem_region(fix->mmio_start, fix->mmio_len);
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
}
- g_options[PM3_OPTIONS_SIZE - 1] = '\0';
- DPRINTK(1, "pm3fb use options: %s\n", g_options);
}
-int init_module(void)
+static struct pci_device_id pm3fb_id_table[] = {
+ { PCI_VENDOR_ID_3DLABS, 0x0a,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+ 0xff0000, 0 },
+ { 0, }
+};
+
+/* For PCI drivers */
+static struct pci_driver pm3fb_driver = {
+ .name = "pm3fb",
+ .id_table = pm3fb_id_table,
+ .probe = pm3fb_probe,
+ .remove = __devexit_p(pm3fb_remove),
+};
+
+MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
+
+int __init pm3fb_init(void)
{
- DTRACE;
+ /*
+ * For kernel boot options (in 'video=pm3fb:<options>' format)
+ */
+#ifndef MODULE
+ char *option = NULL;
- pm3fb_build_options();
+ if (fb_get_options("pm3fb", &option))
+ return -ENODEV;
+ pm3fb_setup(option);
+#endif
- pm3fb_init();
+ return pci_register_driver(&pm3fb_driver);
+}
- return 0;
+static void __exit pm3fb_exit(void)
+{
+ pci_unregister_driver(&pm3fb_driver);
}
-void cleanup_module(void)
+#ifdef MODULE
+ /*
+ * Setup
+ */
+
+/*
+ * Only necessary if your driver takes special options,
+ * otherwise we fall back on the generic fb_setup().
+ */
+int __init pm3fb_setup(char *options)
{
- DTRACE;
- {
- unsigned long i;
- struct pm3fb_info *l_fb_info;
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- l_fb_info = &(fb_info[i]);
- pci_dev_put(l_fb_info->dev);
- if (l_fb_info->dev != NULL && !(disable[l_fb_info->board_num])) {
- if (l_fb_info->vIOBase != (unsigned char *) -1) {
- pm3fb_unmapIO(l_fb_info);
- release_mem_region(l_fb_info->p_fb,
- l_fb_info->fb_size);
- release_mem_region(l_fb_info->pIOBase,
- PM3_REGS_SIZE);
- }
- unregister_framebuffer(&l_fb_info->gen.info);
- }
- }
- }
+ /* Parse user speficied options (`video=pm3fb:') */
+ return 0;
}
#endif /* MODULE */
+
+module_init(pm3fb_init);
+module_exit(pm3fb_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index 76e6ce353c8e..a0e22ac483a3 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -70,8 +70,6 @@ static int riva_gpio_getscl(void* data)
if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04)
val = 1;
- val = VGA_RD08(par->riva.PCIO, 0x3d5);
-
return val;
}
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 756fafb41d78..d11735895a01 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -796,23 +796,6 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
return 0;
}
-/* Get capabilities of accelerator based on the mode */
-
-static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
- struct fb_var_screeninfo *var)
-{
- if (var->bits_per_pixel == 0) {
- /* can only support 256 8x16 bitmap */
- caps->x = 1 << (8 - 1);
- caps->y = 1 << (16 - 1);
- caps->len = 256;
- } else {
- caps->x = ~(u32)0;
- caps->y = ~(u32)0;
- caps->len = ~(u32)0;
- }
-}
-
/* ------------------------------------------------------------------------- */
/* Frame buffer operations */
@@ -829,7 +812,7 @@ static struct fb_ops s3fb_ops = {
.fb_fillrect = s3fb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = s3fb_imageblit,
- .fb_get_caps = s3fb_get_caps,
+ .fb_get_caps = svga_get_caps,
};
/* ------------------------------------------------------------------------- */
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 842b5cd054c6..836a612af977 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -14,7 +14,7 @@
* of it.
*
* First the roles of struct fb_info and struct display have changed. Struct
- * display will go away. The way the the new framebuffer console code will
+ * display will go away. The way the new framebuffer console code will
* work is that it will act to translate data about the tty/console in
* struct vc_data to data in a device independent way in struct fb_info. Then
* various functions in struct fb_ops will be called to store the device
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c
index 079cdc911e48..25df928d37d8 100644
--- a/drivers/video/svgalib.c
+++ b/drivers/video/svgalib.c
@@ -347,6 +347,23 @@ int svga_get_tilemax(struct fb_info *info)
return 256;
}
+/* Get capabilities of accelerator based on the mode */
+
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+ struct fb_var_screeninfo *var)
+{
+ if (var->bits_per_pixel == 0) {
+ /* can only support 256 8x16 bitmap */
+ caps->x = 1 << (8 - 1);
+ caps->y = 1 << (16 - 1);
+ caps->len = 256;
+ } else {
+ caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
+ caps->y = ~(u32)0;
+ caps->len = ~(u32)0;
+ }
+}
+EXPORT_SYMBOL(svga_get_caps);
/* ------------------------------------------------------------------------- */
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
new file mode 100644
index 000000000000..5e9755e464a1
--- /dev/null
+++ b/drivers/video/vt8623fb.c
@@ -0,0 +1,927 @@
+/*
+ * linux/drivers/video/vt8623fb.c - fbdev driver for
+ * integrated graphic core in VIA VT8623 [CLE266] chipset
+ *
+ * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Code is based on s3fb, some parts are from David Boucher's viafb
+ * (http://davesdomain.org.uk/viafb/)
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct vt8623fb_info {
+ char __iomem *mmio_base;
+ int mtrr_reg;
+ struct vgastate state;
+ struct mutex open_lock;
+ unsigned int ref_count;
+ u32 pseudo_palette[16];
+};
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static const struct svga_fb_format vt8623fb_formats[] = {
+ { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1,
+ FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+/* {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, */
+ {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2},
+ SVGA_FORMAT_END
+};
+
+static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3,
+ 60000, 300000, 14318};
+
+/* CRT timing register sets */
+
+struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
+
+struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
+struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
+
+struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
+
+struct svga_timing_regs vt8623_timing_regs = {
+ vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs,
+ vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs,
+ vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs,
+ vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]");
+
+module_param(mode, charp, 0644);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static struct fb_tile_ops vt8623fb_tile_ops = {
+ .fb_settile = svga_settile,
+ .fb_tilecopy = svga_tilecopy,
+ .fb_tilefill = svga_tilefill,
+ .fb_tileblit = svga_tileblit,
+ .fb_tilecursor = svga_tilecursor,
+ .fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+ return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* vt8623fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = expand_color(image->fg_color);
+ u32 bg = expand_color(image->bg_color);
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = *(src++) * 0x01010101;
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+}
+
+/* vt8623fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ u32 fg = expand_color(rect->color);
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ int x, y;
+
+ dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+ + ((rect->dx / 8) * 4);
+
+ for (y = 0; y < rect->height; y++) {
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < rect->width; x += 8) {
+ fb_writel(fg, dst++);
+ }
+ dst1 += info->fix.line_length;
+ }
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+ return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) |
+ ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF;
+}
+
+/* vt8623fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = image->fg_color * 0x11111111;
+ u32 bg = image->bg_color * 0x11111111;
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = expand_pixel(*(src++));
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+}
+
+static void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+ && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+ if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+ vt8623fb_iplan_imageblit(info, image);
+ else
+ vt8623fb_cfb4_imageblit(info, image);
+ } else
+ cfb_imageblit(info, image);
+}
+
+static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ if ((info->var.bits_per_pixel == 4)
+ && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+ && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+ vt8623fb_iplan_fillrect(info, rect);
+ else
+ cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+ u16 m, n, r;
+ u8 regval;
+ int rv;
+
+ rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+ if (rv < 0) {
+ printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+ return;
+ }
+
+ /* Set VGA misc register */
+ regval = vga_r(NULL, VGA_MIS_R);
+ vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+
+ /* Set clock registers */
+ vga_wseq(NULL, 0x46, (n | (r << 6)));
+ vga_wseq(NULL, 0x47, m);
+
+ udelay(1000);
+
+ /* PLL reset */
+ svga_wseq_mask(0x40, 0x02, 0x02);
+ svga_wseq_mask(0x40, 0x00, 0x02);
+}
+
+
+static int vt8623fb_open(struct fb_info *info, int user)
+{
+ struct vt8623fb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ memset(&(par->state), 0, sizeof(struct vgastate));
+ par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+ par->state.num_crtc = 0xA2;
+ par->state.num_seq = 0x50;
+ save_vga(&(par->state));
+ }
+
+ par->ref_count++;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+static int vt8623fb_release(struct fb_info *info, int user)
+{
+ struct vt8623fb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ return -EINVAL;
+ }
+
+ if (par->ref_count == 1)
+ restore_vga(&(par->state));
+
+ par->ref_count--;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int rv, mem, step;
+
+ /* Find appropriate format */
+ rv = svga_match_format (vt8623fb_formats, var, NULL);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+ return rv;
+ }
+
+ /* Do not allow to have real resoulution larger than virtual */
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ /* Round up xres_virtual to have proper alignment of lines */
+ step = vt8623fb_formats[rv].xresstep - 1;
+ var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+ /* Check whether have enough memory */
+ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+ if (mem > info->screen_size)
+ {
+ printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+ return -EINVAL;
+ }
+
+ /* Text mode is limited to 256 kB of memory */
+ if ((var->bits_per_pixel == 0) && (mem > (256*1024)))
+ {
+ printk(KERN_ERR "fb%d: text framebuffer size too large (%d kB requested, 256 kB possible)\n", info->node, mem >> 10);
+ return -EINVAL;
+ }
+
+ rv = svga_check_timings (&vt8623_timing_regs, var, info->node);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+ return rv;
+ }
+
+ /* Interlaced mode not supported */
+ if (var->vmode & FB_VMODE_INTERLACED)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+static int vt8623fb_set_par(struct fb_info *info)
+{
+ u32 mode, offset_value, fetch_value, screen_size;
+ u32 bpp = info->var.bits_per_pixel;
+
+ if (bpp != 0) {
+ info->fix.ypanstep = 1;
+ info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+ info->flags &= ~FBINFO_MISC_TILEBLITTING;
+ info->tileops = NULL;
+
+ /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+ info->pixmap.blit_y = ~(u32)0;
+
+ offset_value = (info->var.xres_virtual * bpp) / 64;
+ fetch_value = ((info->var.xres * bpp) / 128) + 4;
+
+ if (bpp == 4)
+ fetch_value = (info->var.xres / 8) + 8; /* + 0 is OK */
+
+ screen_size = info->var.yres_virtual * info->fix.line_length;
+ } else {
+ info->fix.ypanstep = 16;
+ info->fix.line_length = 0;
+
+ info->flags |= FBINFO_MISC_TILEBLITTING;
+ info->tileops = &vt8623fb_tile_ops;
+
+ /* supports 8x16 tiles only */
+ info->pixmap.blit_x = 1 << (8 - 1);
+ info->pixmap.blit_y = 1 << (16 - 1);
+
+ offset_value = info->var.xres_virtual / 16;
+ fetch_value = (info->var.xres / 8) + 8;
+ screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+ }
+
+ info->var.xoffset = 0;
+ info->var.yoffset = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+
+ /* Unlock registers */
+ svga_wseq_mask(0x10, 0x01, 0x01);
+ svga_wcrt_mask(0x11, 0x00, 0x80);
+ svga_wcrt_mask(0x47, 0x00, 0x01);
+
+ /* Device, screen and sync off */
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x36, 0x30, 0x30);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+
+ /* Set default values */
+ svga_set_default_gfx_regs();
+ svga_set_default_atc_regs();
+ svga_set_default_seq_regs();
+ svga_set_default_crt_regs();
+ svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF);
+ svga_wcrt_multi(vt8623_start_address_regs, 0);
+
+ svga_wcrt_multi(vt8623_offset_regs, offset_value);
+ svga_wseq_multi(vt8623_fetch_count_regs, fetch_value);
+
+ if (info->var.vmode & FB_VMODE_DOUBLE)
+ svga_wcrt_mask(0x09, 0x80, 0x80);
+ else
+ svga_wcrt_mask(0x09, 0x00, 0x80);
+
+ svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus
+ svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus
+ svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold
+ vga_wseq(NULL, 0x17, 0x1F); // FIFO depth
+ vga_wseq(NULL, 0x18, 0x4E);
+ svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ?
+
+ vga_wcrt(NULL, 0x32, 0x00);
+ vga_wcrt(NULL, 0x34, 0x00);
+ vga_wcrt(NULL, 0x6A, 0x80);
+ vga_wcrt(NULL, 0x6A, 0xC0);
+
+ vga_wgfx(NULL, 0x20, 0x00);
+ vga_wgfx(NULL, 0x21, 0x00);
+ vga_wgfx(NULL, 0x22, 0x00);
+
+ /* Set SR15 according to number of bits per pixel */
+ mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix));
+ switch (mode) {
+ case 0:
+ pr_debug("fb%d: text mode\n", info->node);
+ svga_set_textmode_vga_regs();
+ svga_wseq_mask(0x15, 0x00, 0xFE);
+ svga_wcrt_mask(0x11, 0x60, 0x70);
+ break;
+ case 1:
+ pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+ svga_wseq_mask(0x15, 0x20, 0xFE);
+ svga_wcrt_mask(0x11, 0x00, 0x70);
+ break;
+ case 2:
+ pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+ svga_wseq_mask(0x15, 0x00, 0xFE);
+ svga_wcrt_mask(0x11, 0x00, 0x70);
+ break;
+ case 3:
+ pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+ svga_wseq_mask(0x15, 0x22, 0xFE);
+ break;
+ case 4:
+ pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+ svga_wseq_mask(0x15, 0xB6, 0xFE);
+ break;
+ case 5:
+ pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+ svga_wseq_mask(0x15, 0xAE, 0xFE);
+ break;
+ default:
+ printk(KERN_ERR "vt8623fb: unsupported mode - bug\n");
+ return (-EINVAL);
+ }
+
+ vt8623_set_pixclock(info, info->var.pixclock);
+ svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1,
+ (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1,
+ 1, info->node);
+
+ memset_io(info->screen_base, 0x00, screen_size);
+
+ /* Device and screen back on */
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+
+ return 0;
+}
+
+
+static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ switch (fb->var.bits_per_pixel) {
+ case 0:
+ case 4:
+ if (regno >= 16)
+ return -EINVAL;
+
+ outb(0x0F, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 8:
+ if (regno >= 256)
+ return -EINVAL;
+
+ outb(0xFF, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 16:
+ if (regno >= 16)
+ return 0;
+
+ if (fb->var.green.length == 5)
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+ ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+ else if (fb->var.green.length == 6)
+ ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ else
+ return -EINVAL;
+ break;
+ case 24:
+ case 32:
+ if (regno >= 16)
+ return 0;
+
+ /* ((transp & 0xFF00) << 16) */
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+ (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int vt8623fb_blank(int blank_mode, struct fb_info *info)
+{
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ pr_debug("fb%d: unblank\n", info->node);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+ break;
+ case FB_BLANK_NORMAL:
+ pr_debug("fb%d: blank\n", info->node);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ pr_debug("fb%d: DPMS standby (hsync off)\n", info->node);
+ svga_wcrt_mask(0x36, 0x10, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node);
+ svga_wcrt_mask(0x36, 0x20, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_POWERDOWN:
+ pr_debug("fb%d: DPMS off (no sync)\n", info->node);
+ svga_wcrt_mask(0x36, 0x30, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ unsigned int offset;
+
+ /* Calculate the offset */
+ if (var->bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset;
+ offset = offset >> 3;
+ } else {
+ offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * var->bits_per_pixel / 8);
+ offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1);
+ }
+
+ /* Set the offset */
+ svga_wcrt_multi(vt8623_start_address_regs, offset);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops vt8623fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = vt8623fb_open,
+ .fb_release = vt8623fb_release,
+ .fb_check_var = vt8623fb_check_var,
+ .fb_set_par = vt8623fb_set_par,
+ .fb_setcolreg = vt8623fb_setcolreg,
+ .fb_blank = vt8623fb_blank,
+ .fb_pan_display = vt8623fb_pan_display,
+ .fb_fillrect = vt8623fb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = vt8623fb_imageblit,
+ .fb_get_caps = svga_get_caps,
+};
+
+
+/* PCI probe */
+
+static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct fb_info *info;
+ struct vt8623fb_info *par;
+ unsigned int memsize1, memsize2;
+ int rc;
+
+ /* Ignore secondary VGA device because there is no VGA arbitration */
+ if (! svga_primary_device(dev)) {
+ dev_info(&(dev->dev), "ignoring secondary device\n");
+ return -ENODEV;
+ }
+
+ /* Allocate and fill driver data structure */
+ info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL);
+ if (! info) {
+ dev_err(&(dev->dev), "cannot allocate memory\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ mutex_init(&par->open_lock);
+
+ info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+ info->fbops = &vt8623fb_ops;
+
+ /* Prepare PCI device */
+
+ rc = pci_enable_device(dev);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot enable PCI device\n");
+ goto err_enable_device;
+ }
+
+ rc = pci_request_regions(dev, "vt8623fb");
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ goto err_request_regions;
+ }
+
+ info->fix.smem_start = pci_resource_start(dev, 0);
+ info->fix.smem_len = pci_resource_len(dev, 0);
+ info->fix.mmio_start = pci_resource_start(dev, 1);
+ info->fix.mmio_len = pci_resource_len(dev, 1);
+
+ /* Map physical IO memory address into kernel space */
+ info->screen_base = pci_iomap(dev, 0, 0);
+ if (! info->screen_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ goto err_iomap_1;
+ }
+
+ par->mmio_base = pci_iomap(dev, 1, 0);
+ if (! par->mmio_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for MMIO failed\n");
+ goto err_iomap_2;
+ }
+
+ /* Find how many physical memory there is on card */
+ memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1;
+ memsize2 = vga_rseq(NULL, 0x39) << 2;
+
+ if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2))
+ info->screen_size = memsize1 << 20;
+ else {
+ dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2);
+ info->screen_size = 16 << 20;
+ }
+
+ info->fix.smem_len = info->screen_size;
+ strcpy(info->fix.id, "VIA VT8623");
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->pseudo_palette = (void*)par->pseudo_palette;
+
+ /* Prepare startup mode */
+
+ rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ if (! ((rc == 1) || (rc == 2))) {
+ rc = -EINVAL;
+ dev_err(&(dev->dev), "mode %s not found\n", mode);
+ goto err_find_mode;
+ }
+
+ rc = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot allocate colormap\n");
+ goto err_alloc_cmap;
+ }
+
+ rc = register_framebuffer(info);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot register framebugger\n");
+ goto err_reg_fb;
+ }
+
+ printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+ pci_name(dev), info->fix.smem_len >> 20);
+
+ /* Record a reference to the driver data */
+ pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+ if (mtrr) {
+ par->mtrr_reg = -1;
+ par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+
+ return 0;
+
+ /* Error handling */
+err_reg_fb:
+ fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+ pci_iounmap(dev, par->mmio_base);
+err_iomap_2:
+ pci_iounmap(dev, info->screen_base);
+err_iomap_1:
+ pci_release_regions(dev);
+err_request_regions:
+/* pci_disable_device(dev); */
+err_enable_device:
+ framebuffer_release(info);
+ return rc;
+}
+
+/* PCI remove */
+
+static void __devexit vt8623_pci_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ if (info) {
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+#endif
+
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ pci_iounmap(dev, info->screen_base);
+ pci_iounmap(dev, par->mmio_base);
+ pci_release_regions(dev);
+/* pci_disable_device(dev); */
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+ }
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ dev_info(&(dev->dev), "suspend\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ fb_set_suspend(info, 1);
+
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+
+ return 0;
+}
+
+
+/* PCI resume */
+
+static int vt8623_pci_resume(struct pci_dev* dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ dev_info(&(dev->dev), "resume\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+
+ if (pci_enable_device(dev))
+ goto fail;
+
+ pci_set_master(dev);
+
+ vt8623fb_set_par(info);
+ fb_set_suspend(info, 0);
+
+ mutex_unlock(&(par->open_lock));
+fail:
+ release_console_sem();
+
+ return 0;
+}
+#else
+#define vt8623_pci_suspend NULL
+#define vt8623_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id vt8623_devices[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, vt8623_devices);
+
+static struct pci_driver vt8623fb_pci_driver = {
+ .name = "vt8623fb",
+ .id_table = vt8623_devices,
+ .probe = vt8623_pci_probe,
+ .remove = __devexit_p(vt8623_pci_remove),
+ .suspend = vt8623_pci_suspend,
+ .resume = vt8623_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit vt8623fb_cleanup(void)
+{
+ pr_debug("vt8623fb: cleaning up\n");
+ pci_unregister_driver(&vt8623fb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+int __init vt8623fb_init(void)
+{
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("vt8623fb", &option))
+ return -ENODEV;
+
+ if (option && *option)
+ mode = option;
+#endif
+
+ pr_debug("vt8623fb: initializing\n");
+ return pci_register_driver(&vt8623fb_pci_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Modularization */
+
+module_init(vt8623fb_init);
+module_exit(vt8623fb_cleanup);