lkml.org 
[lkml]   [2012]   [Feb]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [PATCH v5] [resend] Resurrect Intel740 driver: i740fb
On 02/10/2012 05:59 PM, Ondrej Zary wrote:
> This is a resurrection of an old (like 2.4.19) out-of-tree driver for
> Intel740 graphics cards and adaptation for recent kernels. The old driver by
> Andrey Ulanov is located at: http://sourceforge.net/projects/i740fbdev/files/
>
> This is a new driver based on skeletonfb, using most of the low level HW code
> from the old driver. The DDC code is completely new.
>
> The driver was tested on two 8MB cards: Protac AG240D and Diamond Stealth II
> G460.
>
> Signed-off-by: Ondrej Zary <linux@rainbow-software.org>

Applied. Just for the record, checkpatch complained about

WARNING: simple_strtoul is obsolete, use kstrtoul instead
#1384: FILE: drivers/video/i740fb.c:1296:
+ mtrr = simple_strtoul(opt + 5, NULL, 0);

Feel free to send another patch to fix it, if you like.


Thanks,

Florian Tobias Schandinat

> ---
> Changes in v5:
> - fixed checkpatch problems
> - added Kconfig dependency on FB_DDC
> - cleaned up i740_calc_vclk()
> - fixed SDRAM/SGRAM detection
> - fixed wrong colors in 16bpp mode when neither 555 nor 565 specified
>
> --- linux-3.2.1-orig/drivers/video/Kconfig 2012-01-12 20:42:45.000000000 +0100
> +++ linux-3.2.1/drivers/video/Kconfig 2012-01-23 20:52:32.000000000 +0100
> @@ -1123,6 +1123,18 @@ config FB_RIVA_BACKLIGHT
> help
> Say Y here if you want to control the backlight of your display.
>
> +config FB_I740
> + tristate "Intel740 support (EXPERIMENTAL)"
> + depends on EXPERIMENTAL && FB && PCI
> + select FB_MODE_HELPERS
> + select FB_CFB_FILLRECT
> + select FB_CFB_COPYAREA
> + select FB_CFB_IMAGEBLIT
> + select VGASTATE
> + select FB_DDC
> + help
> + This driver supports graphics cards based on Intel740 chip.
> +
> config FB_I810
> tristate "Intel 810/815 support (EXPERIMENTAL)"
> depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL
> --- linux-3.2.1-orig/drivers/video/Makefile 2012-01-12 20:42:45.000000000 +0100
> +++ linux-3.2.1/drivers/video/Makefile 2012-01-23 20:52:32.000000000 +0100
> @@ -37,6 +37,7 @@ obj-$(CONFIG_FB_GRVGA) += grv
> obj-$(CONFIG_FB_PM2) += pm2fb.o
> obj-$(CONFIG_FB_PM3) += pm3fb.o
>
> +obj-$(CONFIG_FB_I740) += i740fb.o
> obj-$(CONFIG_FB_MATROX) += matrox/
> obj-$(CONFIG_FB_RIVA) += riva/
> obj-$(CONFIG_FB_NVIDIA) += nvidia/
> --- /dev/null 2012-01-24 00:06:39.330222901 +0100
> +++ linux-3.2.1/drivers/video/i740fb.c 2012-01-24 00:01:54.000000000 +0100
> @@ -0,0 +1,1337 @@
> +/*
> + * i740fb - framebuffer driver for Intel740
> + * Copyright (c) 2011 Ondrej Zary
> + *
> + * Based on old i740fb driver (c) 2001-2002 Andrey Ulanov <drey@rt.mipt.ru>
> + * which was partially based on:
> + * VGA 16-color framebuffer driver (c) 1999 Ben Pfaff <pfaffben@debian.org>
> + * and Petr Vandrovec <VANDROVE@vc.cvut.cz>
> + * i740 driver from XFree86 (c) 1998-1999 Precision Insight, Inc., Cedar Park,
> + * Texas.
> + * i740fb by Patrick LERDA, v0.9
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/mm.h>
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/fb.h>
> +#include <linux/init.h>
> +#include <linux/pci.h>
> +#include <linux/pci_ids.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-algo-bit.h>
> +#include <linux/console.h>
> +#include <video/vga.h>
> +
> +#ifdef CONFIG_MTRR
> +#include <asm/mtrr.h>
> +#endif
> +
> +#include "i740_reg.h"
> +
> +static char *mode_option __devinitdata;
> +
> +#ifdef CONFIG_MTRR
> +static int mtrr __devinitdata = 1;
> +#endif
> +
> +struct i740fb_par {
> + unsigned char __iomem *regs;
> + bool has_sgram;
> +#ifdef CONFIG_MTRR
> + int mtrr_reg;
> +#endif
> + bool ddc_registered;
> + struct i2c_adapter ddc_adapter;
> + struct i2c_algo_bit_data ddc_algo;
> + u32 pseudo_palette[16];
> + struct mutex open_lock;
> + unsigned int ref_count;
> +
> + u8 crtc[VGA_CRT_C];
> + u8 atc[VGA_ATT_C];
> + u8 gdc[VGA_GFX_C];
> + u8 seq[VGA_SEQ_C];
> + u8 misc;
> + u8 vss;
> +
> + /* i740 specific registers */
> + u8 display_cntl;
> + u8 pixelpipe_cfg0;
> + u8 pixelpipe_cfg1;
> + u8 pixelpipe_cfg2;
> + u8 video_clk2_m;
> + u8 video_clk2_n;
> + u8 video_clk2_mn_msbs;
> + u8 video_clk2_div_sel;
> + u8 pll_cntl;
> + u8 address_mapping;
> + u8 io_cntl;
> + u8 bitblt_cntl;
> + u8 ext_vert_total;
> + u8 ext_vert_disp_end;
> + u8 ext_vert_sync_start;
> + u8 ext_vert_blank_start;
> + u8 ext_horiz_total;
> + u8 ext_horiz_blank;
> + u8 ext_offset;
> + u8 interlace_cntl;
> + u32 lmi_fifo_watermark;
> + u8 ext_start_addr;
> + u8 ext_start_addr_hi;
> +};
> +
> +#define DACSPEED8 203
> +#define DACSPEED16 163
> +#define DACSPEED24_SG 136
> +#define DACSPEED24_SD 128
> +#define DACSPEED32 86
> +
> +static struct fb_fix_screeninfo i740fb_fix __devinitdata = {
> + .id = "i740fb",
> + .type = FB_TYPE_PACKED_PIXELS,
> + .visual = FB_VISUAL_TRUECOLOR,
> + .xpanstep = 8,
> + .ypanstep = 1,
> + .accel = FB_ACCEL_NONE,
> +};
> +
> +static inline void i740outb(struct i740fb_par *par, u16 port, u8 val)
> +{
> + vga_mm_w(par->regs, port, val);
> +}
> +static inline u8 i740inb(struct i740fb_par *par, u16 port)
> +{
> + return vga_mm_r(par->regs, port);
> +}
> +static inline void i740outreg(struct i740fb_par *par, u16 port, u8 reg, u8 val)
> +{
> + vga_mm_w_fast(par->regs, port, reg, val);
> +}
> +static inline u8 i740inreg(struct i740fb_par *par, u16 port, u8 reg)
> +{
> + vga_mm_w(par->regs, port, reg);
> + return vga_mm_r(par->regs, port+1);
> +}
> +static inline void i740outreg_mask(struct i740fb_par *par, u16 port, u8 reg,
> + u8 val, u8 mask)
> +{
> + vga_mm_w_fast(par->regs, port, reg, (val & mask)
> + | (i740inreg(par, port, reg) & ~mask));
> +}
> +
> +#define REG_DDC_DRIVE 0x62
> +#define REG_DDC_STATE 0x63
> +#define DDC_SCL (1 << 3)
> +#define DDC_SDA (1 << 2)
> +
> +static void i740fb_ddc_setscl(void *data, int val)
> +{
> + struct i740fb_par *par = data;
> +
> + i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SCL, DDC_SCL);
> + i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SCL : 0, DDC_SCL);
> +}
> +
> +static void i740fb_ddc_setsda(void *data, int val)
> +{
> + struct i740fb_par *par = data;
> +
> + i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SDA, DDC_SDA);
> + i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SDA : 0, DDC_SDA);
> +}
> +
> +static int i740fb_ddc_getscl(void *data)
> +{
> + struct i740fb_par *par = data;
> +
> + i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SCL);
> +
> + return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SCL);
> +}
> +
> +static int i740fb_ddc_getsda(void *data)
> +{
> + struct i740fb_par *par = data;
> +
> + i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SDA);
> +
> + return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SDA);
> +}
> +
> +static int __devinit i740fb_setup_ddc_bus(struct fb_info *info)
> +{
> + struct i740fb_par *par = info->par;
> +
> + strlcpy(par->ddc_adapter.name, info->fix.id,
> + sizeof(par->ddc_adapter.name));
> + par->ddc_adapter.owner = THIS_MODULE;
> + par->ddc_adapter.class = I2C_CLASS_DDC;
> + par->ddc_adapter.algo_data = &par->ddc_algo;
> + par->ddc_adapter.dev.parent = info->device;
> + par->ddc_algo.setsda = i740fb_ddc_setsda;
> + par->ddc_algo.setscl = i740fb_ddc_setscl;
> + par->ddc_algo.getsda = i740fb_ddc_getsda;
> + par->ddc_algo.getscl = i740fb_ddc_getscl;
> + par->ddc_algo.udelay = 10;
> + par->ddc_algo.timeout = 20;
> + par->ddc_algo.data = par;
> +
> + i2c_set_adapdata(&par->ddc_adapter, par);
> +
> + return i2c_bit_add_bus(&par->ddc_adapter);
> +}
> +
> +static int i740fb_open(struct fb_info *info, int user)
> +{
> + struct i740fb_par *par = info->par;
> +
> + mutex_lock(&(par->open_lock));
> + par->ref_count++;
> + mutex_unlock(&(par->open_lock));
> +
> + return 0;
> +}
> +
> +static int i740fb_release(struct fb_info *info, int user)
> +{
> + struct i740fb_par *par = info->par;
> +
> + mutex_lock(&(par->open_lock));
> + if (par->ref_count == 0) {
> + printk(KERN_ERR "fb%d: release called with zero refcount\n",
> + info->node);
> + mutex_unlock(&(par->open_lock));
> + return -EINVAL;
> + }
> +
> + par->ref_count--;
> + mutex_unlock(&(par->open_lock));
> +
> + return 0;
> +}
> +
> +static u32 i740_calc_fifo(struct i740fb_par *par, u32 freq, int bpp)
> +{
> + /*
> + * Would like to calculate these values automatically, but a generic
> + * algorithm does not seem possible. Note: These FIFO water mark
> + * values were tested on several cards and seem to eliminate the
> + * all of the snow and vertical banding, but fine adjustments will
> + * probably be required for other cards.
> + */
> +
> + u32 wm;
> +
> + switch (bpp) {
> + case 8:
> + if (freq > 200)
> + wm = 0x18120000;
> + else if (freq > 175)
> + wm = 0x16110000;
> + else if (freq > 135)
> + wm = 0x120E0000;
> + else
> + wm = 0x100D0000;
> + break;
> + case 15:
> + case 16:
> + if (par->has_sgram) {
> + if (freq > 140)
> + wm = 0x2C1D0000;
> + else if (freq > 120)
> + wm = 0x2C180000;
> + else if (freq > 100)
> + wm = 0x24160000;
> + else if (freq > 90)
> + wm = 0x18120000;
> + else if (freq > 50)
> + wm = 0x16110000;
> + else if (freq > 32)
> + wm = 0x13100000;
> + else
> + wm = 0x120E0000;
> + } else {
> + if (freq > 160)
> + wm = 0x28200000;
> + else if (freq > 140)
> + wm = 0x2A1E0000;
> + else if (freq > 130)
> + wm = 0x2B1A0000;
> + else if (freq > 120)
> + wm = 0x2C180000;
> + else if (freq > 100)
> + wm = 0x24180000;
> + else if (freq > 90)
> + wm = 0x18120000;
> + else if (freq > 50)
> + wm = 0x16110000;
> + else if (freq > 32)
> + wm = 0x13100000;
> + else
> + wm = 0x120E0000;
> + }
> + break;
> + case 24:
> + if (par->has_sgram) {
> + if (freq > 130)
> + wm = 0x31200000;
> + else if (freq > 120)
> + wm = 0x2E200000;
> + else if (freq > 100)
> + wm = 0x2C1D0000;
> + else if (freq > 80)
> + wm = 0x25180000;
> + else if (freq > 64)
> + wm = 0x24160000;
> + else if (freq > 49)
> + wm = 0x18120000;
> + else if (freq > 32)
> + wm = 0x16110000;
> + else
> + wm = 0x13100000;
> + } else {
> + if (freq > 120)
> + wm = 0x311F0000;
> + else if (freq > 100)
> + wm = 0x2C1D0000;
> + else if (freq > 80)
> + wm = 0x25180000;
> + else if (freq > 64)
> + wm = 0x24160000;
> + else if (freq > 49)
> + wm = 0x18120000;
> + else if (freq > 32)
> + wm = 0x16110000;
> + else
> + wm = 0x13100000;
> + }
> + break;
> + case 32:
> + if (par->has_sgram) {
> + if (freq > 80)
> + wm = 0x2A200000;
> + else if (freq > 60)
> + wm = 0x281A0000;
> + else if (freq > 49)
> + wm = 0x25180000;
> + else if (freq > 32)
> + wm = 0x18120000;
> + else
> + wm = 0x16110000;
> + } else {
> + if (freq > 80)
> + wm = 0x29200000;
> + else if (freq > 60)
> + wm = 0x281A0000;
> + else if (freq > 49)
> + wm = 0x25180000;
> + else if (freq > 32)
> + wm = 0x18120000;
> + else
> + wm = 0x16110000;
> + }
> + break;
> + }
> +
> + return wm;
> +}
> +
> +/* clock calculation from i740fb by Patrick LERDA */
> +
> +#define I740_RFREQ 1000000
> +#define TARGET_MAX_N 30
> +#define I740_FFIX (1 << 8)
> +#define I740_RFREQ_FIX (I740_RFREQ / I740_FFIX)
> +#define I740_REF_FREQ (6667 * I740_FFIX / 100) /* 66.67 MHz */
> +#define I740_MAX_VCO_FREQ (450 * I740_FFIX) /* 450 MHz */
> +
> +static void i740_calc_vclk(u32 freq, struct i740fb_par *par)
> +{
> + const u32 err_max = freq / (200 * I740_RFREQ / I740_FFIX);
> + const u32 err_target = freq / (1000 * I740_RFREQ / I740_FFIX);
> + u32 err_best = 512 * I740_FFIX;
> + u32 f_err, f_vco;
> + int m_best = 0, n_best = 0, p_best = 0, d_best = 0;
> + int m, n;
> +
> + p_best = min(15, ilog2(I740_MAX_VCO_FREQ / (freq / I740_RFREQ_FIX)));
> + d_best = 0;
> + f_vco = (freq * (1 << p_best)) / I740_RFREQ_FIX;
> + freq = freq / I740_RFREQ_FIX;
> +
> + n = 2;
> + do {
> + n++;
> + m = ((f_vco * n) / I740_REF_FREQ + 2) / 4;
> +
> + if (m < 3)
> + m = 3;
> +
> + {
> + u32 f_out = (((m * I740_REF_FREQ * (4 << 2 * d_best))
> + / n) + ((1 << p_best) / 2)) / (1 << p_best);
> +
> + f_err = (freq - f_out);
> +
> + if (abs(f_err) < err_max) {
> + m_best = m;
> + n_best = n;
> + err_best = f_err;
> + }
> + }
> + } while ((abs(f_err) >= err_target) &&
> + ((n <= TARGET_MAX_N) || (abs(err_best) > err_max)));
> +
> + if (abs(f_err) < err_target) {
> + m_best = m;
> + n_best = n;
> + }
> +
> + par->video_clk2_m = (m_best - 2) & 0xFF;
> + par->video_clk2_n = (n_best - 2) & 0xFF;
> + par->video_clk2_mn_msbs = ((((n_best - 2) >> 4) & VCO_N_MSBS)
> + | (((m_best - 2) >> 8) & VCO_M_MSBS));
> + par->video_clk2_div_sel =
> + ((p_best << 4) | (d_best ? 4 : 0) | REF_DIV_1);
> +}
> +
> +static int i740fb_decode_var(const struct fb_var_screeninfo *var,
> + struct i740fb_par *par, struct fb_info *info)
> +{
> + /*
> + * Get the video params out of 'var'.
> + * If a value doesn't fit, round it up, if it's too big, return -EINVAL.
> + */
> +
> + u32 xres, right, hslen, left, xtotal;
> + u32 yres, lower, vslen, upper, ytotal;
> + u32 vxres, xoffset, vyres, yoffset;
> + u32 bpp, base, dacspeed24, mem;
> + u8 r7;
> + int i;
> +
> + dev_dbg(info->device, "decode_var: xres: %i, yres: %i, xres_v: %i, xres_v: %i\n",
> + var->xres, var->yres, var->xres_virtual, var->xres_virtual);
> + dev_dbg(info->device, " xoff: %i, yoff: %i, bpp: %i, graysc: %i\n",
> + var->xoffset, var->yoffset, var->bits_per_pixel,
> + var->grayscale);
> + dev_dbg(info->device, " activate: %i, nonstd: %i, vmode: %i\n",
> + var->activate, var->nonstd, var->vmode);
> + dev_dbg(info->device, " pixclock: %i, hsynclen:%i, vsynclen:%i\n",
> + var->pixclock, var->hsync_len, var->vsync_len);
> + dev_dbg(info->device, " left: %i, right: %i, up:%i, lower:%i\n",
> + var->left_margin, var->right_margin, var->upper_margin,
> + var->lower_margin);
> +
> +
> + bpp = var->bits_per_pixel;
> + switch (bpp) {
> + case 1 ... 8:
> + bpp = 8;
> + if ((1000000 / var->pixclock) > DACSPEED8) {
> + dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 8bpp)\n",
> + 1000000 / var->pixclock, DACSPEED8);
> + return -EINVAL;
> + }
> + break;
> + case 9 ... 15:
> + bpp = 15;
> + case 16:
> + if ((1000000 / var->pixclock) > DACSPEED16) {
> + dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n",
> + 1000000 / var->pixclock, DACSPEED16);
> + return -EINVAL;
> + }
> + break;
> + case 17 ... 24:
> + bpp = 24;
> + dacspeed24 = par->has_sgram ? DACSPEED24_SG : DACSPEED24_SD;
> + if ((1000000 / var->pixclock) > dacspeed24) {
> + dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 24bpp)\n",
> + 1000000 / var->pixclock, dacspeed24);
> + return -EINVAL;
> + }
> + break;
> + case 25 ... 32:
> + bpp = 32;
> + if ((1000000 / var->pixclock) > DACSPEED32) {
> + dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 32bpp)\n",
> + 1000000 / var->pixclock, DACSPEED32);
> + return -EINVAL;
> + }
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + xres = ALIGN(var->xres, 8);
> + vxres = ALIGN(var->xres_virtual, 16);
> + if (vxres < xres)
> + vxres = xres;
> +
> + xoffset = ALIGN(var->xoffset, 8);
> + if (xres + xoffset > vxres)
> + xoffset = vxres - xres;
> +
> + left = ALIGN(var->left_margin, 8);
> + right = ALIGN(var->right_margin, 8);
> + hslen = ALIGN(var->hsync_len, 8);
> +
> + yres = var->yres;
> + vyres = var->yres_virtual;
> + if (yres > vyres)
> + vyres = yres;
> +
> + yoffset = var->yoffset;
> + if (yres + yoffset > vyres)
> + yoffset = vyres - yres;
> +
> + lower = var->lower_margin;
> + vslen = var->vsync_len;
> + upper = var->upper_margin;
> +
> + mem = vxres * vyres * ((bpp + 1) / 8);
> + if (mem > info->screen_size) {
> + dev_err(info->device, "not enough video memory (%d KB requested, %ld KB avaliable)\n",
> + mem >> 10, info->screen_size >> 10);
> + return -ENOMEM;
> + }
> +
> + if (yoffset + yres > vyres)
> + yoffset = vyres - yres;
> +
> + xtotal = xres + right + hslen + left;
> + ytotal = yres + lower + vslen + upper;
> +
> + par->crtc[VGA_CRTC_H_TOTAL] = (xtotal >> 3) - 5;
> + par->crtc[VGA_CRTC_H_DISP] = (xres >> 3) - 1;
> + par->crtc[VGA_CRTC_H_BLANK_START] = ((xres + right) >> 3) - 1;
> + par->crtc[VGA_CRTC_H_SYNC_START] = (xres + right) >> 3;
> + par->crtc[VGA_CRTC_H_SYNC_END] = (((xres + right + hslen) >> 3) & 0x1F)
> + | ((((xres + right + hslen) >> 3) & 0x20) << 2);
> + par->crtc[VGA_CRTC_H_BLANK_END] = ((xres + right + hslen) >> 3 & 0x1F)
> + | 0x80;
> +
> + par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
> +
> + r7 = 0x10; /* disable linecompare */
> + if (ytotal & 0x100)
> + r7 |= 0x01;
> + if (ytotal & 0x200)
> + r7 |= 0x20;
> +
> + par->crtc[VGA_CRTC_PRESET_ROW] = 0;
> + par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
> + if (var->vmode & FB_VMODE_DOUBLE)
> + par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
> + par->crtc[VGA_CRTC_CURSOR_START] = 0x00;
> + par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
> + par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
> + par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
> + par->crtc[VGA_CRTC_V_DISP_END] = yres-1;
> + if ((yres-1) & 0x100)
> + r7 |= 0x02;
> + if ((yres-1) & 0x200)
> + r7 |= 0x40;
> +
> + par->crtc[VGA_CRTC_V_BLANK_START] = yres + lower - 1;
> + par->crtc[VGA_CRTC_V_SYNC_START] = yres + lower - 1;
> + if ((yres + lower - 1) & 0x100)
> + r7 |= 0x0C;
> + if ((yres + lower - 1) & 0x200) {
> + par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20;
> + r7 |= 0x80;
> + }
> +
> + /* disabled IRQ */
> + par->crtc[VGA_CRTC_V_SYNC_END] =
> + ((yres + lower - 1 + vslen) & 0x0F) & ~0x10;
> + /* 0x7F for VGA, but some SVGA chips require all 8 bits to be set */
> + par->crtc[VGA_CRTC_V_BLANK_END] = (yres + lower - 1 + vslen) & 0xFF;
> +
> + par->crtc[VGA_CRTC_UNDERLINE] = 0x00;
> + par->crtc[VGA_CRTC_MODE] = 0xC3 ;
> + par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
> + par->crtc[VGA_CRTC_OVERFLOW] = r7;
> +
> + par->vss = 0x00; /* 3DA */
> +
> + for (i = 0x00; i < 0x10; i++)
> + par->atc[i] = i;
> + par->atc[VGA_ATC_MODE] = 0x81;
> + par->atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
> + par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
> + par->atc[VGA_ATC_COLOR_PAGE] = 0x00;
> +
> + par->misc = 0xC3;
> + if (var->sync & FB_SYNC_HOR_HIGH_ACT)
> + par->misc &= ~0x40;
> + if (var->sync & FB_SYNC_VERT_HIGH_ACT)
> + par->misc &= ~0x80;
> +
> + par->seq[VGA_SEQ_CLOCK_MODE] = 0x01;
> + par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
> + par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
> + par->seq[VGA_SEQ_MEMORY_MODE] = 0x06;
> +
> + par->gdc[VGA_GFX_SR_VALUE] = 0x00;
> + par->gdc[VGA_GFX_SR_ENABLE] = 0x00;
> + par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
> + par->gdc[VGA_GFX_DATA_ROTATE] = 0x00;
> + par->gdc[VGA_GFX_PLANE_READ] = 0;
> + par->gdc[VGA_GFX_MODE] = 0x02;
> + par->gdc[VGA_GFX_MISC] = 0x05;
> + par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
> + par->gdc[VGA_GFX_BIT_MASK] = 0xFF;
> +
> + base = (yoffset * vxres + (xoffset & ~7)) >> 2;
> + switch (bpp) {
> + case 8:
> + par->crtc[VGA_CRTC_OFFSET] = vxres >> 3;
> + par->ext_offset = vxres >> 11;
> + par->pixelpipe_cfg1 = DISPLAY_8BPP_MODE;
> + par->bitblt_cntl = COLEXP_8BPP;
> + break;
> + case 15: /* 0rrrrrgg gggbbbbb */
> + case 16: /* rrrrrggg gggbbbbb */
> + par->pixelpipe_cfg1 = (var->green.length == 6) ?
> + DISPLAY_16BPP_MODE : DISPLAY_15BPP_MODE;
> + par->crtc[VGA_CRTC_OFFSET] = vxres >> 2;
> + par->ext_offset = vxres >> 10;
> + par->bitblt_cntl = COLEXP_16BPP;
> + base *= 2;
> + break;
> + case 24:
> + par->crtc[VGA_CRTC_OFFSET] = (vxres * 3) >> 3;
> + par->ext_offset = (vxres * 3) >> 11;
> + par->pixelpipe_cfg1 = DISPLAY_24BPP_MODE;
> + par->bitblt_cntl = COLEXP_24BPP;
> + base &= 0xFFFFFFFE; /* ...ignore the last bit. */
> + base *= 3;
> + break;
> + case 32:
> + par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
> + par->ext_offset = vxres >> 9;
> + par->pixelpipe_cfg1 = DISPLAY_32BPP_MODE;
> + par->bitblt_cntl = COLEXP_RESERVED; /* Unimplemented on i740 */
> + base *= 4;
> + break;
> + }
> +
> + par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
> + par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >> 8;
> + par->ext_start_addr =
> + ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
> + par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
> +
> + par->pixelpipe_cfg0 = DAC_8_BIT;
> +
> + par->pixelpipe_cfg2 = DISPLAY_GAMMA_ENABLE | OVERLAY_GAMMA_ENABLE;
> + par->io_cntl = EXTENDED_CRTC_CNTL;
> + par->address_mapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE;
> + par->display_cntl = HIRES_MODE;
> +
> + /* Set the MCLK freq */
> + par->pll_cntl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */
> +
> + /* Calculate the extended CRTC regs */
> + par->ext_vert_total = (ytotal - 2) >> 8;
> + par->ext_vert_disp_end = (yres - 1) >> 8;
> + par->ext_vert_sync_start = (yres + lower) >> 8;
> + par->ext_vert_blank_start = (yres + lower) >> 8;
> + par->ext_horiz_total = ((xtotal >> 3) - 5) >> 8;
> + par->ext_horiz_blank = (((xres + right) >> 3) & 0x40) >> 6;
> +
> + par->interlace_cntl = INTERLACE_DISABLE;
> +
> + /* Set the overscan color to 0. (NOTE: This only affects >8bpp mode) */
> + par->atc[VGA_ATC_OVERSCAN] = 0;
> +
> + /* Calculate VCLK that most closely matches the requested dot clock */
> + i740_calc_vclk((((u32)1e9) / var->pixclock) * (u32)(1e3), par);
> +
> + /* Since we program the clocks ourselves, always use VCLK2. */
> + par->misc |= 0x0C;
> +
> + /* Calculate the FIFO Watermark and Burst Length. */
> + par->lmi_fifo_watermark =
> + i740_calc_fifo(par, 1000000 / var->pixclock, bpp);
> +
> + return 0;
> +}
> +
> +static int i740fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
> +{
> + switch (var->bits_per_pixel) {
> + case 8:
> + var->red.offset = var->green.offset = var->blue.offset = 0;
> + var->red.length = var->green.length = var->blue.length = 8;
> + break;
> + case 16:
> + switch (var->green.length) {
> + default:
> + case 5:
> + var->red.offset = 10;
> + var->green.offset = 5;
> + var->blue.offset = 0;
> + var->red.length = 5;
> + var->green.length = 5;
> + var->blue.length = 5;
> + break;
> + case 6:
> + var->red.offset = 11;
> + var->green.offset = 5;
> + var->blue.offset = 0;
> + var->red.length = var->blue.length = 5;
> + break;
> + }
> + break;
> + case 24:
> + var->red.offset = 16;
> + var->green.offset = 8;
> + var->blue.offset = 0;
> + var->red.length = var->green.length = var->blue.length = 8;
> + break;
> + case 32:
> + var->transp.offset = 24;
> + var->red.offset = 16;
> + var->green.offset = 8;
> + var->blue.offset = 0;
> + var->transp.length = 8;
> + var->red.length = var->green.length = var->blue.length = 8;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + if (var->xres > var->xres_virtual)
> + var->xres_virtual = var->xres;
> +
> + if (var->yres > var->yres_virtual)
> + var->yres_virtual = var->yres;
> +
> + if (info->monspecs.hfmax && info->monspecs.vfmax &&
> + info->monspecs.dclkmax && fb_validate_mode(var, info) < 0)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static void vga_protect(struct i740fb_par *par)
> +{
> + /* disable the display */
> + i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0x20, 0x20);
> +
> + i740inb(par, 0x3DA);
> + i740outb(par, VGA_ATT_W, 0x00); /* enable pallete access */
> +}
> +
> +static void vga_unprotect(struct i740fb_par *par)
> +{
> + /* reenable display */
> + i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0, 0x20);
> +
> + i740inb(par, 0x3DA);
> + i740outb(par, VGA_ATT_W, 0x20); /* disable pallete access */
> +}
> +
> +static int i740fb_set_par(struct fb_info *info)
> +{
> + struct i740fb_par *par = info->par;
> + u32 itemp;
> + int i;
> +
> + i = i740fb_decode_var(&info->var, par, info);
> + if (i)
> + return i;
> +
> + memset(info->screen_base, 0, info->screen_size);
> +
> + vga_protect(par);
> +
> + i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE);
> +
> + mdelay(1);
> +
> + i740outreg(par, XRX, VCLK2_VCO_M, par->video_clk2_m);
> + i740outreg(par, XRX, VCLK2_VCO_N, par->video_clk2_n);
> + i740outreg(par, XRX, VCLK2_VCO_MN_MSBS, par->video_clk2_mn_msbs);
> + i740outreg(par, XRX, VCLK2_VCO_DIV_SEL, par->video_clk2_div_sel);
> +
> + i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0,
> + par->pixelpipe_cfg0 & DAC_8_BIT, 0x80);
> +
> + i740inb(par, 0x3DA);
> + i740outb(par, 0x3C0, 0x00);
> +
> + /* update misc output register */
> + i740outb(par, VGA_MIS_W, par->misc | 0x01);
> +
> + /* synchronous reset on */
> + i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x01);
> + /* write sequencer registers */
> + i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE,
> + par->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
> + for (i = 2; i < VGA_SEQ_C; i++)
> + i740outreg(par, VGA_SEQ_I, i, par->seq[i]);
> +
> + /* synchronous reset off */
> + i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x03);
> +
> + /* deprotect CRT registers 0-7 */
> + i740outreg(par, VGA_CRT_IC, VGA_CRTC_V_SYNC_END,
> + par->crtc[VGA_CRTC_V_SYNC_END]);
> +
> + /* write CRT registers */
> + for (i = 0; i < VGA_CRT_C; i++)
> + i740outreg(par, VGA_CRT_IC, i, par->crtc[i]);
> +
> + /* write graphics controller registers */
> + for (i = 0; i < VGA_GFX_C; i++)
> + i740outreg(par, VGA_GFX_I, i, par->gdc[i]);
> +
> + /* write attribute controller registers */
> + for (i = 0; i < VGA_ATT_C; i++) {
> + i740inb(par, VGA_IS1_RC); /* reset flip-flop */
> + i740outb(par, VGA_ATT_IW, i);
> + i740outb(par, VGA_ATT_IW, par->atc[i]);
> + }
> +
> + i740inb(par, VGA_IS1_RC);
> + i740outb(par, VGA_ATT_IW, 0x20);
> +
> + i740outreg(par, VGA_CRT_IC, EXT_VERT_TOTAL, par->ext_vert_total);
> + i740outreg(par, VGA_CRT_IC, EXT_VERT_DISPLAY, par->ext_vert_disp_end);
> + i740outreg(par, VGA_CRT_IC, EXT_VERT_SYNC_START,
> + par->ext_vert_sync_start);
> + i740outreg(par, VGA_CRT_IC, EXT_VERT_BLANK_START,
> + par->ext_vert_blank_start);
> + i740outreg(par, VGA_CRT_IC, EXT_HORIZ_TOTAL, par->ext_horiz_total);
> + i740outreg(par, VGA_CRT_IC, EXT_HORIZ_BLANK, par->ext_horiz_blank);
> + i740outreg(par, VGA_CRT_IC, EXT_OFFSET, par->ext_offset);
> + i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, par->ext_start_addr_hi);
> + i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, par->ext_start_addr);
> +
> + i740outreg_mask(par, VGA_CRT_IC, INTERLACE_CNTL,
> + par->interlace_cntl, INTERLACE_ENABLE);
> + i740outreg_mask(par, XRX, ADDRESS_MAPPING, par->address_mapping, 0x1F);
> + i740outreg_mask(par, XRX, BITBLT_CNTL, par->bitblt_cntl, COLEXP_MODE);
> + i740outreg_mask(par, XRX, DISPLAY_CNTL,
> + par->display_cntl, VGA_WRAP_MODE | GUI_MODE);
> + i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, par->pixelpipe_cfg0, 0x9B);
> + i740outreg_mask(par, XRX, PIXPIPE_CONFIG_2, par->pixelpipe_cfg2, 0x0C);
> +
> + i740outreg(par, XRX, PLL_CNTL, par->pll_cntl);
> +
> + i740outreg_mask(par, XRX, PIXPIPE_CONFIG_1,
> + par->pixelpipe_cfg1, DISPLAY_COLOR_MODE);
> +
> + itemp = readl(par->regs + FWATER_BLC);
> + itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK);
> + itemp |= par->lmi_fifo_watermark;
> + writel(itemp, par->regs + FWATER_BLC);
> +
> + i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ);
> +
> + i740outreg_mask(par, MRX, COL_KEY_CNTL_1, 0, BLANK_DISP_OVERLAY);
> + i740outreg_mask(par, XRX, IO_CTNL,
> + par->io_cntl, EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL);
> +
> + if (par->pixelpipe_cfg1 != DISPLAY_8BPP_MODE) {
> + i740outb(par, VGA_PEL_MSK, 0xFF);
> + i740outb(par, VGA_PEL_IW, 0x00);
> + for (i = 0; i < 256; i++) {
> + itemp = (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2;
> + i740outb(par, VGA_PEL_D, itemp);
> + i740outb(par, VGA_PEL_D, itemp);
> + i740outb(par, VGA_PEL_D, itemp);
> + }
> + }
> +
> + /* Wait for screen to stabilize. */
> + mdelay(50);
> + vga_unprotect(par);
> +
> + info->fix.line_length =
> + info->var.xres_virtual * info->var.bits_per_pixel / 8;
> + if (info->var.bits_per_pixel == 8)
> + info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
> + else
> + info->fix.visual = FB_VISUAL_TRUECOLOR;
> +
> + return 0;
> +}
> +
> +static int i740fb_setcolreg(unsigned regno, unsigned red, unsigned green,
> + unsigned blue, unsigned transp,
> + struct fb_info *info)
> +{
> + u32 r, g, b;
> +
> + dev_dbg(info->device, "setcolreg: regno: %i, red=%d, green=%d, blue=%d, transp=%d, bpp=%d\n",
> + regno, red, green, blue, transp, info->var.bits_per_pixel);
> +
> + switch (info->fix.visual) {
> + case FB_VISUAL_PSEUDOCOLOR:
> + if (regno >= 256)
> + return -EINVAL;
> + i740outb(info->par, VGA_PEL_IW, regno);
> + i740outb(info->par, VGA_PEL_D, red >> 8);
> + i740outb(info->par, VGA_PEL_D, green >> 8);
> + i740outb(info->par, VGA_PEL_D, blue >> 8);
> + break;
> + case FB_VISUAL_TRUECOLOR:
> + if (regno >= 16)
> + return -EINVAL;
> + r = (red >> (16 - info->var.red.length))
> + << info->var.red.offset;
> + b = (blue >> (16 - info->var.blue.length))
> + << info->var.blue.offset;
> + g = (green >> (16 - info->var.green.length))
> + << info->var.green.offset;
> + ((u32 *) info->pseudo_palette)[regno] = r | g | b;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int i740fb_pan_display(struct fb_var_screeninfo *var,
> + struct fb_info *info)
> +{
> + struct i740fb_par *par = info->par;
> + u32 base = (var->yoffset * info->var.xres_virtual
> + + (var->xoffset & ~7)) >> 2;
> +
> + dev_dbg(info->device, "pan_display: xoffset: %i yoffset: %i base: %i\n",
> + var->xoffset, var->yoffset, base);
> +
> + switch (info->var.bits_per_pixel) {
> + case 8:
> + break;
> + case 15:
> + case 16:
> + base *= 2;
> + break;
> + case 24:
> + /*
> + * The last bit does not seem to have any effect on the start
> + * address register in 24bpp mode, so...
> + */
> + base &= 0xFFFFFFFE; /* ...ignore the last bit. */
> + base *= 3;
> + break;
> + case 32:
> + base *= 4;
> + break;
> + }
> +
> + par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
> + par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >> 8;
> + par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
> + par->ext_start_addr =
> + ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
> +
> + i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_LO, base & 0x000000FF);
> + i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_HI,
> + (base & 0x0000FF00) >> 8);
> + i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI,
> + (base & 0x3FC00000) >> 22);
> + i740outreg(par, VGA_CRT_IC, EXT_START_ADDR,
> + ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE);
> +
> + return 0;
> +}
> +
> +static int i740fb_blank(int blank_mode, struct fb_info *info)
> +{
> + struct i740fb_par *par = info->par;
> +
> + unsigned char SEQ01;
> + int DPMSSyncSelect;
> +
> + switch (blank_mode) {
> + case FB_BLANK_UNBLANK:
> + case FB_BLANK_NORMAL:
> + SEQ01 = 0x00;
> + DPMSSyncSelect = HSYNC_ON | VSYNC_ON;
> + break;
> + case FB_BLANK_VSYNC_SUSPEND:
> + SEQ01 = 0x20;
> + DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
> + break;
> + case FB_BLANK_HSYNC_SUSPEND:
> + SEQ01 = 0x20;
> + DPMSSyncSelect = HSYNC_OFF | VSYNC_ON;
> + break;
> + case FB_BLANK_POWERDOWN:
> + SEQ01 = 0x20;
> + DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF;
> + break;
> + default:
> + return -EINVAL;
> + }
> + /* Turn the screen on/off */
> + i740outb(par, SRX, 0x01);
> + SEQ01 |= i740inb(par, SRX + 1) & ~0x20;
> + i740outb(par, SRX, 0x01);
> + i740outb(par, SRX + 1, SEQ01);
> +
> + /* Set the DPMS mode */
> + i740outreg(par, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect);
> +
> + /* Let fbcon do a soft blank for us */
> + return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
> +}
> +
> +static struct fb_ops i740fb_ops = {
> + .owner = THIS_MODULE,
> + .fb_open = i740fb_open,
> + .fb_release = i740fb_release,
> + .fb_check_var = i740fb_check_var,
> + .fb_set_par = i740fb_set_par,
> + .fb_setcolreg = i740fb_setcolreg,
> + .fb_blank = i740fb_blank,
> + .fb_pan_display = i740fb_pan_display,
> + .fb_fillrect = cfb_fillrect,
> + .fb_copyarea = cfb_copyarea,
> + .fb_imageblit = cfb_imageblit,
> +};
> +
> +/* ------------------------------------------------------------------------- */
> +
> +static int __devinit i740fb_probe(struct pci_dev *dev,
> + const struct pci_device_id *ent)
> +{
> + struct fb_info *info;
> + struct i740fb_par *par;
> + int ret, tmp;
> + bool found = false;
> + u8 *edid;
> +
> + info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev));
> + if (!info) {
> + dev_err(&(dev->dev), "cannot allocate framebuffer\n");
> + return -ENOMEM;
> + }
> +
> + par = info->par;
> + mutex_init(&par->open_lock);
> +
> + info->var.activate = FB_ACTIVATE_NOW;
> + info->var.bits_per_pixel = 8;
> + info->fbops = &i740fb_ops;
> + info->pseudo_palette = par->pseudo_palette;
> +
> + ret = pci_enable_device(dev);
> + if (ret) {
> + dev_err(info->device, "cannot enable PCI device\n");
> + goto err_enable_device;
> + }
> +
> + ret = pci_request_regions(dev, info->fix.id);
> + if (ret) {
> + dev_err(info->device, "error requesting regions\n");
> + goto err_request_regions;
> + }
> +
> + info->screen_base = pci_ioremap_bar(dev, 0);
> + if (!info->screen_base) {
> + dev_err(info->device, "error remapping base\n");
> + ret = -ENOMEM;
> + goto err_ioremap_1;
> + }
> +
> + par->regs = pci_ioremap_bar(dev, 1);
> + if (!par->regs) {
> + dev_err(info->device, "error remapping MMIO\n");
> + ret = -ENOMEM;
> + goto err_ioremap_2;
> + }
> +
> + /* detect memory size */
> + if ((i740inreg(par, XRX, DRAM_ROW_TYPE) & DRAM_ROW_1)
> + == DRAM_ROW_1_SDRAM)
> + i740outb(par, XRX, DRAM_ROW_BNDRY_1);
> + else
> + i740outb(par, XRX, DRAM_ROW_BNDRY_0);
> + info->screen_size = i740inb(par, XRX + 1) * 1024 * 1024;
> + /* detect memory type */
> + tmp = i740inreg(par, XRX, DRAM_ROW_CNTL_LO);
> + par->has_sgram = !((tmp & DRAM_RAS_TIMING) ||
> + (tmp & DRAM_RAS_PRECHARGE));
> +
> + printk(KERN_INFO "fb%d: Intel740 on %s, %ld KB %s\n", info->node,
> + pci_name(dev), info->screen_size >> 10,
> + par->has_sgram ? "SGRAM" : "SDRAM");
> +
> + info->fix = i740fb_fix;
> + info->fix.mmio_start = pci_resource_start(dev, 1);
> + info->fix.mmio_len = pci_resource_len(dev, 1);
> + info->fix.smem_start = pci_resource_start(dev, 0);
> + info->fix.smem_len = info->screen_size;
> + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
> +
> + if (i740fb_setup_ddc_bus(info) == 0) {
> + par->ddc_registered = true;
> + edid = fb_ddc_read(&par->ddc_adapter);
> + if (edid) {
> + fb_edid_to_monspecs(edid, &info->monspecs);
> + kfree(edid);
> + if (!info->monspecs.modedb)
> + dev_err(info->device,
> + "error getting mode database\n");
> + else {
> + const struct fb_videomode *m;
> +
> + fb_videomode_to_modelist(
> + info->monspecs.modedb,
> + info->monspecs.modedb_len,
> + &info->modelist);
> + m = fb_find_best_display(&info->monspecs,
> + &info->modelist);
> + if (m) {
> + fb_videomode_to_var(&info->var, m);
> + /* fill all other info->var's fields */
> + if (!i740fb_check_var(&info->var, info))
> + found = true;
> + }
> + }
> + }
> + }
> +
> + if (!mode_option && !found)
> + mode_option = "640x480-8@60";
> +
> + if (mode_option) {
> + ret = fb_find_mode(&info->var, info, mode_option,
> + info->monspecs.modedb,
> + info->monspecs.modedb_len,
> + NULL, info->var.bits_per_pixel);
> + if (!ret || ret == 4) {
> + dev_err(info->device, "mode %s not found\n",
> + mode_option);
> + ret = -EINVAL;
> + }
> + }
> +
> + fb_destroy_modedb(info->monspecs.modedb);
> + info->monspecs.modedb = NULL;
> +
> + /* maximize virtual vertical size for fast scrolling */
> + info->var.yres_virtual = info->fix.smem_len * 8 /
> + (info->var.bits_per_pixel * info->var.xres_virtual);
> +
> + if (ret == -EINVAL)
> + goto err_find_mode;
> +
> + ret = fb_alloc_cmap(&info->cmap, 256, 0);
> + if (ret) {
> + dev_err(info->device, "cannot allocate colormap\n");
> + goto err_alloc_cmap;
> + }
> +
> + ret = register_framebuffer(info);
> + if (ret) {
> + dev_err(info->device, "error registering framebuffer\n");
> + goto err_reg_framebuffer;
> + }
> +
> + printk(KERN_INFO "fb%d: %s frame buffer device\n",
> + info->node, info->fix.id);
> + 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;
> +
> +err_reg_framebuffer:
> + fb_dealloc_cmap(&info->cmap);
> +err_alloc_cmap:
> +err_find_mode:
> + if (par->ddc_registered)
> + i2c_del_adapter(&par->ddc_adapter);
> + pci_iounmap(dev, par->regs);
> +err_ioremap_2:
> + pci_iounmap(dev, info->screen_base);
> +err_ioremap_1:
> + pci_release_regions(dev);
> +err_request_regions:
> +/* pci_disable_device(dev); */
> +err_enable_device:
> + framebuffer_release(info);
> + return ret;
> +}
> +
> +static void __devexit i740fb_remove(struct pci_dev *dev)
> +{
> + struct fb_info *info = pci_get_drvdata(dev);
> +
> + if (info) {
> +#ifdef CONFIG_MTRR
> + struct i740fb_par *par = info->par;
> +
> + 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);
> + if (par->ddc_registered)
> + i2c_del_adapter(&par->ddc_adapter);
> + pci_iounmap(dev, par->regs);
> + 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
> +static int i740fb_suspend(struct pci_dev *dev, pm_message_t state)
> +{
> + struct fb_info *info = pci_get_drvdata(dev);
> + struct i740fb_par *par = info->par;
> +
> + /* don't disable console during hibernation and wakeup from it */
> + if (state.event == PM_EVENT_FREEZE || state.event == PM_EVENT_PRETHAW)
> + return 0;
> +
> + console_lock();
> + mutex_lock(&(par->open_lock));
> +
> + /* do nothing if framebuffer is not active */
> + if (par->ref_count == 0) {
> + mutex_unlock(&(par->open_lock));
> + console_unlock();
> + 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));
> + console_unlock();
> +
> + return 0;
> +}
> +
> +static int i740fb_resume(struct pci_dev *dev)
> +{
> + struct fb_info *info = pci_get_drvdata(dev);
> + struct i740fb_par *par = info->par;
> +
> + console_lock();
> + mutex_lock(&(par->open_lock));
> +
> + if (par->ref_count == 0)
> + goto fail;
> +
> + pci_set_power_state(dev, PCI_D0);
> + pci_restore_state(dev);
> + if (pci_enable_device(dev))
> + goto fail;
> +
> + i740fb_set_par(info);
> + fb_set_suspend(info, 0);
> +
> +fail:
> + mutex_unlock(&(par->open_lock));
> + console_unlock();
> + return 0;
> +}
> +#else
> +#define i740fb_suspend NULL
> +#define i740fb_resume NULL
> +#endif /* CONFIG_PM */
> +
> +#define I740_ID_PCI 0x00d1
> +#define I740_ID_AGP 0x7800
> +
> +static DEFINE_PCI_DEVICE_TABLE(i740fb_id_table) = {
> + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_PCI) },
> + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_AGP) },
> + { 0 }
> +};
> +MODULE_DEVICE_TABLE(pci, i740fb_id_table);
> +
> +static struct pci_driver i740fb_driver = {
> + .name = "i740fb",
> + .id_table = i740fb_id_table,
> + .probe = i740fb_probe,
> + .remove = __devexit_p(i740fb_remove),
> + .suspend = i740fb_suspend,
> + .resume = i740fb_resume,
> +};
> +
> +#ifndef MODULE
> +static int __init i740fb_setup(char *options)
> +{
> + char *opt;
> +
> + if (!options || !*options)
> + return 0;
> +
> + while ((opt = strsep(&options, ",")) != NULL) {
> + if (!*opt)
> + continue;
> +#ifdef CONFIG_MTRR
> + else if (!strncmp(opt, "mtrr:", 5))
> + mtrr = simple_strtoul(opt + 5, NULL, 0);
> +#endif
> + else
> + mode_option = opt;
> + }
> +
> + return 0;
> +}
> +#endif
> +
> +int __init i740fb_init(void)
> +{
> +#ifndef MODULE
> + char *option = NULL;
> +
> + if (fb_get_options("i740fb", &option))
> + return -ENODEV;
> + i740fb_setup(option);
> +#endif
> +
> + return pci_register_driver(&i740fb_driver);
> +}
> +
> +static void __exit i740fb_exit(void)
> +{
> + pci_unregister_driver(&i740fb_driver);
> +}
> +
> +module_init(i740fb_init);
> +module_exit(i740fb_exit);
> +
> +MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("fbdev driver for Intel740");
> +
> +module_param(mode_option, charp, 0444);
> +MODULE_PARM_DESC(mode_option, "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
> --- /dev/null 2012-01-24 00:06:39.330222901 +0100
> +++ linux-3.2.1/drivers/video/i740_reg.h 2012-01-23 22:55:57.000000000 +0100
> @@ -0,0 +1,309 @@
> +/**************************************************************************
> +
> +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
> +All Rights Reserved.
> +
> +Permission is hereby granted, free of charge, to any person obtaining a
> +copy of this software and associated documentation files (the
> +"Software"), to deal in the Software without restriction, including
> +without limitation the rights to use, copy, modify, merge, publish,
> +distribute, sub license, and/or sell copies of the Software, and to
> +permit persons to whom the Software is furnished to do so, subject to
> +the following conditions:
> +
> +The above copyright notice and this permission notice (including the
> +next paragraph) shall be included in all copies or substantial portions
> +of the Software.
> +
> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
> +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
> +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> +
> +**************************************************************************/
> +
> +/*
> + * Authors:
> + * Kevin E. Martin <kevin@precisioninsight.com>
> + */
> +
> +/* I/O register offsets */
> +#define SRX VGA_SEQ_I
> +#define GRX VGA_GFX_I
> +#define ARX VGA_ATT_IW
> +#define XRX 0x3D6
> +#define MRX 0x3D2
> +
> +/* VGA Color Palette Registers */
> +#define DACMASK 0x3C6
> +#define DACSTATE 0x3C7
> +#define DACRX 0x3C7
> +#define DACWX 0x3C8
> +#define DACDATA 0x3C9
> +
> +/* CRT Controller Registers (CRX) */
> +#define START_ADDR_HI 0x0C
> +#define START_ADDR_LO 0x0D
> +#define VERT_SYNC_END 0x11
> +#define EXT_VERT_TOTAL 0x30
> +#define EXT_VERT_DISPLAY 0x31
> +#define EXT_VERT_SYNC_START 0x32
> +#define EXT_VERT_BLANK_START 0x33
> +#define EXT_HORIZ_TOTAL 0x35
> +#define EXT_HORIZ_BLANK 0x39
> +#define EXT_START_ADDR 0x40
> +#define EXT_START_ADDR_ENABLE 0x80
> +#define EXT_OFFSET 0x41
> +#define EXT_START_ADDR_HI 0x42
> +#define INTERLACE_CNTL 0x70
> +#define INTERLACE_ENABLE 0x80
> +#define INTERLACE_DISABLE 0x00
> +
> +/* Miscellaneous Output Register */
> +#define MSR_R 0x3CC
> +#define MSR_W 0x3C2
> +#define IO_ADDR_SELECT 0x01
> +
> +#define MDA_BASE 0x3B0
> +#define CGA_BASE 0x3D0
> +
> +/* System Configuration Extension Registers (XRX) */
> +#define IO_CTNL 0x09
> +#define EXTENDED_ATTR_CNTL 0x02
> +#define EXTENDED_CRTC_CNTL 0x01
> +
> +#define ADDRESS_MAPPING 0x0A
> +#define PACKED_MODE_ENABLE 0x04
> +#define LINEAR_MODE_ENABLE 0x02
> +#define PAGE_MAPPING_ENABLE 0x01
> +
> +#define BITBLT_CNTL 0x20
> +#define COLEXP_MODE 0x30
> +#define COLEXP_8BPP 0x00
> +#define COLEXP_16BPP 0x10
> +#define COLEXP_24BPP 0x20
> +#define COLEXP_RESERVED 0x30
> +#define CHIP_RESET 0x02
> +#define BITBLT_STATUS 0x01
> +
> +#define DISPLAY_CNTL 0x40
> +#define VGA_WRAP_MODE 0x02
> +#define VGA_WRAP_AT_256KB 0x00
> +#define VGA_NO_WRAP 0x02
> +#define GUI_MODE 0x01
> +#define STANDARD_VGA_MODE 0x00
> +#define HIRES_MODE 0x01
> +
> +#define DRAM_ROW_TYPE 0x50
> +#define DRAM_ROW_0 0x07
> +#define DRAM_ROW_0_SDRAM 0x00
> +#define DRAM_ROW_0_EMPTY 0x07
> +#define DRAM_ROW_1 0x38
> +#define DRAM_ROW_1_SDRAM 0x00
> +#define DRAM_ROW_1_EMPTY 0x38
> +#define DRAM_ROW_CNTL_LO 0x51
> +#define DRAM_CAS_LATENCY 0x10
> +#define DRAM_RAS_TIMING 0x08
> +#define DRAM_RAS_PRECHARGE 0x04
> +#define DRAM_ROW_CNTL_HI 0x52
> +#define DRAM_EXT_CNTL 0x53
> +#define DRAM_REFRESH_RATE 0x03
> +#define DRAM_REFRESH_DISABLE 0x00
> +#define DRAM_REFRESH_60HZ 0x01
> +#define DRAM_REFRESH_FAST_TEST 0x02
> +#define DRAM_REFRESH_RESERVED 0x03
> +#define DRAM_TIMING 0x54
> +#define DRAM_ROW_BNDRY_0 0x55
> +#define DRAM_ROW_BNDRY_1 0x56
> +
> +#define DPMS_SYNC_SELECT 0x61
> +#define VSYNC_CNTL 0x08
> +#define VSYNC_ON 0x00
> +#define VSYNC_OFF 0x08
> +#define HSYNC_CNTL 0x02
> +#define HSYNC_ON 0x00
> +#define HSYNC_OFF 0x02
> +
> +#define PIXPIPE_CONFIG_0 0x80
> +#define DAC_8_BIT 0x80
> +#define DAC_6_BIT 0x00
> +#define HW_CURSOR_ENABLE 0x10
> +#define EXTENDED_PALETTE 0x01
> +
> +#define PIXPIPE_CONFIG_1 0x81
> +#define DISPLAY_COLOR_MODE 0x0F
> +#define DISPLAY_VGA_MODE 0x00
> +#define DISPLAY_8BPP_MODE 0x02
> +#define DISPLAY_15BPP_MODE 0x04
> +#define DISPLAY_16BPP_MODE 0x05
> +#define DISPLAY_24BPP_MODE 0x06
> +#define DISPLAY_32BPP_MODE 0x07
> +
> +#define PIXPIPE_CONFIG_2 0x82
> +#define DISPLAY_GAMMA_ENABLE 0x08
> +#define DISPLAY_GAMMA_DISABLE 0x00
> +#define OVERLAY_GAMMA_ENABLE 0x04
> +#define OVERLAY_GAMMA_DISABLE 0x00
> +
> +#define CURSOR_CONTROL 0xA0
> +#define CURSOR_ORIGIN_SCREEN 0x00
> +#define CURSOR_ORIGIN_DISPLAY 0x10
> +#define CURSOR_MODE 0x07
> +#define CURSOR_MODE_DISABLE 0x00
> +#define CURSOR_MODE_32_4C_AX 0x01
> +#define CURSOR_MODE_128_2C 0x02
> +#define CURSOR_MODE_128_1C 0x03
> +#define CURSOR_MODE_64_3C 0x04
> +#define CURSOR_MODE_64_4C_AX 0x05
> +#define CURSOR_MODE_64_4C 0x06
> +#define CURSOR_MODE_RESERVED 0x07
> +#define CURSOR_BASEADDR_LO 0xA2
> +#define CURSOR_BASEADDR_HI 0xA3
> +#define CURSOR_X_LO 0xA4
> +#define CURSOR_X_HI 0xA5
> +#define CURSOR_X_POS 0x00
> +#define CURSOR_X_NEG 0x80
> +#define CURSOR_Y_LO 0xA6
> +#define CURSOR_Y_HI 0xA7
> +#define CURSOR_Y_POS 0x00
> +#define CURSOR_Y_NEG 0x80
> +
> +#define VCLK2_VCO_M 0xC8
> +#define VCLK2_VCO_N 0xC9
> +#define VCLK2_VCO_MN_MSBS 0xCA
> +#define VCO_N_MSBS 0x30
> +#define VCO_M_MSBS 0x03
> +#define VCLK2_VCO_DIV_SEL 0xCB
> +#define POST_DIV_SELECT 0x70
> +#define POST_DIV_1 0x00
> +#define POST_DIV_2 0x10
> +#define POST_DIV_4 0x20
> +#define POST_DIV_8 0x30
> +#define POST_DIV_16 0x40
> +#define POST_DIV_32 0x50
> +#define VCO_LOOP_DIV_BY_4M 0x00
> +#define VCO_LOOP_DIV_BY_16M 0x04
> +#define REF_CLK_DIV_BY_5 0x02
> +#define REF_DIV_4 0x00
> +#define REF_DIV_1 0x01
> +
> +#define PLL_CNTL 0xCE
> +#define PLL_MEMCLK_SEL 0x03
> +#define PLL_MEMCLK__66667KHZ 0x00
> +#define PLL_MEMCLK__75000KHZ 0x01
> +#define PLL_MEMCLK__88889KHZ 0x02
> +#define PLL_MEMCLK_100000KHZ 0x03
> +
> +/* Multimedia Extension Registers (MRX) */
> +#define ACQ_CNTL_1 0x02
> +#define ACQ_CNTL_2 0x03
> +#define FRAME_CAP_MODE 0x01
> +#define CONT_CAP_MODE 0x00
> +#define SINGLE_CAP_MODE 0x01
> +#define ACQ_CNTL_3 0x04
> +#define COL_KEY_CNTL_1 0x3C
> +#define BLANK_DISP_OVERLAY 0x20
> +
> +/* FIFOs */
> +#define LP_FIFO 0x1000
> +#define HP_FIFO 0x2000
> +#define INSTPNT 0x3040
> +#define LP_FIFO_COUNT 0x3040
> +#define HP_FIFO_COUNT 0x3041
> +
> +/* FIFO Commands */
> +#define CLIENT 0xE0000000
> +#define CLIENT_2D 0x60000000
> +
> +/* Command Parser Mode Register */
> +#define COMPARS 0x3038
> +#define TWO_D_INST_DISABLE 0x08
> +#define THREE_D_INST_DISABLE 0x04
> +#define STATE_VAR_UPDATE_DISABLE 0x02
> +#define PAL_STIP_DISABLE 0x01
> +
> +/* Interrupt Control Registers */
> +#define IER 0x3030
> +#define IIR 0x3032
> +#define IMR 0x3034
> +#define ISR 0x3036
> +#define VMIINTB_EVENT 0x2000
> +#define GPIO4_INT 0x1000
> +#define DISP_FLIP_EVENT 0x0800
> +#define DVD_PORT_DMA 0x0400
> +#define DISP_VBLANK 0x0200
> +#define FIFO_EMPTY_DMA_DONE 0x0100
> +#define INST_PARSER_ERROR 0x0080
> +#define USER_DEFINED 0x0040
> +#define BREAKPOINT 0x0020
> +#define DISP_HORIZ_COUNT 0x0010
> +#define DISP_VSYNC 0x0008
> +#define CAPTURE_HORIZ_COUNT 0x0004
> +#define CAPTURE_VSYNC 0x0002
> +#define THREE_D_PIPE_FLUSHED 0x0001
> +
> +/* FIFO Watermark and Burst Length Control Register */
> +#define FWATER_BLC 0x00006000
> +#define LMI_BURST_LENGTH 0x7F000000
> +#define LMI_FIFO_WATERMARK 0x003F0000
> +#define AGP_BURST_LENGTH 0x00007F00
> +#define AGP_FIFO_WATERMARK 0x0000003F
> +
> +/* BitBLT Registers */
> +#define SRC_DST_PITCH 0x00040000
> +#define DST_PITCH 0x1FFF0000
> +#define SRC_PITCH 0x00001FFF
> +#define COLEXP_BG_COLOR 0x00040004
> +#define COLEXP_FG_COLOR 0x00040008
> +#define MONO_SRC_CNTL 0x0004000C
> +#define MONO_USE_COLEXP 0x00000000
> +#define MONO_USE_SRCEXP 0x08000000
> +#define MONO_DATA_ALIGN 0x07000000
> +#define MONO_BIT_ALIGN 0x01000000
> +#define MONO_BYTE_ALIGN 0x02000000
> +#define MONO_WORD_ALIGN 0x03000000
> +#define MONO_DWORD_ALIGN 0x04000000
> +#define MONO_QWORD_ALIGN 0x05000000
> +#define MONO_SRC_INIT_DSCRD 0x003F0000
> +#define MONO_SRC_RIGHT_CLIP 0x00003F00
> +#define MONO_SRC_LEFT_CLIP 0x0000003F
> +#define BITBLT_CONTROL 0x00040010
> +#define BLTR_STATUS 0x80000000
> +#define DYN_DEPTH 0x03000000
> +#define DYN_DEPTH_8BPP 0x00000000
> +#define DYN_DEPTH_16BPP 0x01000000
> +#define DYN_DEPTH_24BPP 0x02000000
> +#define DYN_DEPTH_32BPP 0x03000000 /* Unimplemented on the i740 */
> +#define DYN_DEPTH_ENABLE 0x00800000
> +#define PAT_VERT_ALIGN 0x00700000
> +#define SOLID_PAT_SELECT 0x00080000
> +#define PAT_IS_IN_COLOR 0x00000000
> +#define PAT_IS_MONO 0x00040000
> +#define MONO_PAT_TRANSP 0x00020000
> +#define COLOR_TRANSP_ROP 0x00000000
> +#define COLOR_TRANSP_DST 0x00008000
> +#define COLOR_TRANSP_EQ 0x00000000
> +#define COLOR_TRANSP_NOT_EQ 0x00010000
> +#define COLOR_TRANSP_ENABLE 0x00004000
> +#define MONO_SRC_TRANSP 0x00002000
> +#define SRC_IS_IN_COLOR 0x00000000
> +#define SRC_IS_MONO 0x00001000
> +#define SRC_USE_SRC_ADDR 0x00000000
> +#define SRC_USE_BLTDATA 0x00000400
> +#define BLT_TOP_TO_BOT 0x00000000
> +#define BLT_BOT_TO_TOP 0x00000200
> +#define BLT_LEFT_TO_RIGHT 0x00000000
> +#define BLT_RIGHT_TO_LEFT 0x00000100
> +#define BLT_ROP 0x000000FF
> +#define BLT_PAT_ADDR 0x00040014
> +#define BLT_SRC_ADDR 0x00040018
> +#define BLT_DST_ADDR 0x0004001C
> +#define BLT_DST_H_W 0x00040020
> +#define BLT_DST_HEIGHT 0x1FFF0000
> +#define BLT_DST_WIDTH 0x00001FFF
> +#define SRCEXP_BG_COLOR 0x00040024
> +#define SRCEXP_FG_COLOR 0x00040028
> +#define BLTDATA 0x00050000
>
>
>



\
 
 \ /
  Last update: 2012-02-16 02:27    [W:0.097 / U:6.308 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site