diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2011-03-25 18:41:20 +0300 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2011-03-25 18:41:20 +0300 |
commit | 7bf7e370d5919112c223a269462cd0b546903829 (patch) | |
tree | 03ccc715239df14ae168277dbccc9d9cf4d8a2c8 /drivers/video/s3fb.c | |
parent | 68b1a1e786f29c900fa1c516a402e24f0ece622a (diff) | |
parent | d39dd11c3e6a7af5c20bfac40594db36cf270f42 (diff) | |
download | linux-7bf7e370d5919112c223a269462cd0b546903829.tar.xz |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-linus-1
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6: (9356 commits)
[media] rc: update for bitop name changes
fs: simplify iget & friends
fs: pull inode->i_lock up out of writeback_single_inode
fs: rename inode_lock to inode_hash_lock
fs: move i_wb_list out from under inode_lock
fs: move i_sb_list out from under inode_lock
fs: remove inode_lock from iput_final and prune_icache
fs: Lock the inode LRU list separately
fs: factor inode disposal
fs: protect inode->i_state with inode->i_lock
lib, arch: add filter argument to show_mem and fix private implementations
SLUB: Write to per cpu data when allocating it
slub: Fix debugobjects with lockless fastpath
autofs4: Do not potentially dereference NULL pointer returned by fget() in autofs_dev_ioctl_setpipefd()
autofs4 - remove autofs4_lock
autofs4 - fix d_manage() return on rcu-walk
autofs4 - fix autofs4_expire_indirect() traversal
autofs4 - fix dentry leak in autofs4_expire_direct()
autofs4 - reinstate last used update on access
vfs - check non-mountpoint dentry might block in __follow_mount_rcu()
...
NOTE!
This merge commit was created to fix compilation error. The block
tree was merged upstream and removed the 'elv_queue_empty()'
function which the new 'mtdswap' driver is using. So a simple
merge of the mtd tree with upstream does not compile. And the
mtd tree has already be published, so re-basing it is not an option.
To fix this unfortunate situation, I had to merge upstream into the
mtd-2.6.git tree without committing, put the fixup patch on top of
this, and then commit this. The result is that we do not have commits
which do not compile.
In other words, this merge commit "merges" 3 things: the MTD tree, the
upstream tree, and the fixup patch.
Diffstat (limited to 'drivers/video/s3fb.c')
-rw-r--r-- | drivers/video/s3fb.c | 357 |
1 files changed, 219 insertions, 138 deletions
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index dce8c97b4333..ddedad9cd069 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -22,7 +22,7 @@ #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 <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ #include <video/vga.h> #ifdef CONFIG_MTRR @@ -64,6 +64,8 @@ static const struct svga_fb_format s3fb_formats[] = { static const struct svga_pll s3_pll = {3, 129, 3, 33, 0, 3, 35000, 240000, 14318}; +static const struct svga_pll s3_trio3d_pll = {3, 129, 3, 31, 0, 4, + 230000, 460000, 14318}; static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512}; @@ -72,7 +74,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge", "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX", "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P", - "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"}; + "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X", + "S3 Trio3D"}; #define CHIP_UNKNOWN 0x00 #define CHIP_732_TRIO32 0x01 @@ -93,6 +96,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", #define CHIP_360_TRIO3D_1X 0x10 #define CHIP_362_TRIO3D_2X 0x11 #define CHIP_368_TRIO3D_2X 0x12 +#define CHIP_365_TRIO3D 0x13 #define CHIP_XXX_TRIO 0x80 #define CHIP_XXX_TRIO64V2_DXGX 0x81 @@ -119,9 +123,11 @@ static const struct vga_regset s3_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, static const struct vga_regset s3_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; static const struct vga_regset s3_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x5E, 6, 6}, VGA_REGSET_END}; -static const struct vga_regset s3_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x31, 4, 5}, {0x51, 0, 1}, VGA_REGSET_END}; +static const struct vga_regset s3_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x69, 0, 4}, VGA_REGSET_END}; static const struct vga_regset s3_offset_regs[] = {{0x13, 0, 7}, {0x51, 4, 5}, VGA_REGSET_END}; /* set 0x43 bit 2 to 0 */ +static const struct vga_regset s3_dtpc_regs[] = {{0x3B, 0, 7}, {0x5D, 6, 6}, VGA_REGSET_END}; + static const struct svga_timing_regs s3_timing_regs = { s3_h_total_regs, s3_h_display_regs, s3_h_blank_start_regs, s3_h_blank_end_regs, s3_h_sync_start_regs, s3_h_sync_end_regs, @@ -188,12 +194,19 @@ static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map) } } +static void s3fb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) +{ + struct s3fb_info *par = info->par; + + svga_tilecursor(par->state.vgabase, info, cursor); +} + static struct fb_tile_ops s3fb_tile_ops = { .fb_settile = svga_settile, .fb_tilecopy = svga_tilecopy, .fb_tilefill = svga_tilefill, .fb_tileblit = svga_tileblit, - .fb_tilecursor = svga_tilecursor, + .fb_tilecursor = s3fb_tilecursor, .fb_get_tilemax = svga_get_tilemax, }; @@ -202,7 +215,7 @@ static struct fb_tile_ops s3fb_fast_tile_ops = { .fb_tilecopy = svga_tilecopy, .fb_tilefill = svga_tilefill, .fb_tileblit = svga_tileblit, - .fb_tilecursor = svga_tilecursor, + .fb_tilecursor = s3fb_tilecursor, .fb_get_tilemax = svga_get_tilemax, }; @@ -334,33 +347,34 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock) u8 regval; int rv; - rv = svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node); + rv = svga_compute_pll((par->chip == CHIP_365_TRIO3D) ? &s3_trio3d_pll : &s3_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); + regval = vga_r(par->state.vgabase, VGA_MIS_R); + vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); /* Set S3 clock registers */ if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X) { - vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */ - vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */ + vga_wseq(par->state.vgabase, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */ + vga_wseq(par->state.vgabase, 0x29, r >> 2); /* remaining highest bit of r */ } else - vga_wseq(NULL, 0x12, (n - 2) | (r << 5)); - vga_wseq(NULL, 0x13, m - 2); + vga_wseq(par->state.vgabase, 0x12, (n - 2) | (r << 5)); + vga_wseq(par->state.vgabase, 0x13, m - 2); udelay(1000); /* Activate clock - write 0, 1, 0 to seq/15 bit 5 */ - regval = vga_rseq (NULL, 0x15); /* | 0x80; */ - vga_wseq(NULL, 0x15, regval & ~(1<<5)); - vga_wseq(NULL, 0x15, regval | (1<<5)); - vga_wseq(NULL, 0x15, regval & ~(1<<5)); + regval = vga_rseq (par->state.vgabase, 0x15); /* | 0x80; */ + vga_wseq(par->state.vgabase, 0x15, regval & ~(1<<5)); + vga_wseq(par->state.vgabase, 0x15, regval | (1<<5)); + vga_wseq(par->state.vgabase, 0x15, regval & ~(1<<5)); } @@ -372,7 +386,10 @@ static int s3fb_open(struct fb_info *info, int user) mutex_lock(&(par->open_lock)); if (par->ref_count == 0) { + void __iomem *vgabase = par->state.vgabase; + memset(&(par->state), 0, sizeof(struct vgastate)); + par->state.vgabase = vgabase; par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; par->state.num_crtc = 0x70; par->state.num_seq = 0x20; @@ -470,6 +487,7 @@ static int s3fb_set_par(struct fb_info *info) struct s3fb_info *par = info->par; u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes; u32 bpp = info->var.bits_per_pixel; + u32 htotal, hsstart; if (bpp != 0) { info->fix.ypanstep = 1; @@ -504,99 +522,112 @@ static int s3fb_set_par(struct fb_info *info) info->var.activate = FB_ACTIVATE_NOW; /* Unlock registers */ - vga_wcrt(NULL, 0x38, 0x48); - vga_wcrt(NULL, 0x39, 0xA5); - vga_wseq(NULL, 0x08, 0x06); - svga_wcrt_mask(0x11, 0x00, 0x80); + vga_wcrt(par->state.vgabase, 0x38, 0x48); + vga_wcrt(par->state.vgabase, 0x39, 0xA5); + vga_wseq(par->state.vgabase, 0x08, 0x06); + svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80); /* Blank screen and turn off sync */ - svga_wseq_mask(0x01, 0x20, 0x20); - svga_wcrt_mask(0x17, 0x00, 0x80); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + svga_wcrt_mask(par->state.vgabase, 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(s3_line_compare_regs, 0xFFFFFFFF); - svga_wcrt_multi(s3_start_address_regs, 0); + svga_set_default_gfx_regs(par->state.vgabase); + svga_set_default_atc_regs(par->state.vgabase); + svga_set_default_seq_regs(par->state.vgabase); + svga_set_default_crt_regs(par->state.vgabase); + svga_wcrt_multi(par->state.vgabase, s3_line_compare_regs, 0xFFFFFFFF); + svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, 0); /* S3 specific initialization */ - svga_wcrt_mask(0x58, 0x10, 0x10); /* enable linear framebuffer */ - svga_wcrt_mask(0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB */ + svga_wcrt_mask(par->state.vgabase, 0x58, 0x10, 0x10); /* enable linear framebuffer */ + svga_wcrt_mask(par->state.vgabase, 0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB */ -/* svga_wcrt_mask(0x33, 0x08, 0x08); */ /* DDR ? */ -/* svga_wcrt_mask(0x43, 0x01, 0x01); */ /* DDR ? */ - svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */ - svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */ +/* svga_wcrt_mask(par->state.vgabase, 0x33, 0x08, 0x08); */ /* DDR ? */ +/* svga_wcrt_mask(par->state.vgabase, 0x43, 0x01, 0x01); */ /* DDR ? */ + svga_wcrt_mask(par->state.vgabase, 0x33, 0x00, 0x08); /* no DDR ? */ + svga_wcrt_mask(par->state.vgabase, 0x43, 0x00, 0x01); /* no DDR ? */ - svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */ + svga_wcrt_mask(par->state.vgabase, 0x5D, 0x00, 0x28); /* Clear strange HSlen bits */ -/* svga_wcrt_mask(0x58, 0x03, 0x03); */ +/* svga_wcrt_mask(par->state.vgabase, 0x58, 0x03, 0x03); */ -/* svga_wcrt_mask(0x53, 0x12, 0x13); */ /* enable MMIO */ -/* svga_wcrt_mask(0x40, 0x08, 0x08); */ /* enable write buffer */ +/* svga_wcrt_mask(par->state.vgabase, 0x53, 0x12, 0x13); */ /* enable MMIO */ +/* svga_wcrt_mask(par->state.vgabase, 0x40, 0x08, 0x08); */ /* enable write buffer */ /* Set the offset register */ pr_debug("fb%d: offset register : %d\n", info->node, offset_value); - svga_wcrt_multi(s3_offset_regs, offset_value); + svga_wcrt_multi(par->state.vgabase, s3_offset_regs, offset_value); if (par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) { - vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ - vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ - vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ - vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ + vga_wcrt(par->state.vgabase, 0x54, 0x18); /* M parameter */ + vga_wcrt(par->state.vgabase, 0x60, 0xff); /* N parameter */ + vga_wcrt(par->state.vgabase, 0x61, 0xff); /* L parameter */ + vga_wcrt(par->state.vgabase, 0x62, 0xff); /* L parameter */ } - vga_wcrt(NULL, 0x3A, 0x35); - svga_wattr(0x33, 0x00); + vga_wcrt(par->state.vgabase, 0x3A, 0x35); + svga_wattr(par->state.vgabase, 0x33, 0x00); if (info->var.vmode & FB_VMODE_DOUBLE) - svga_wcrt_mask(0x09, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80); else - svga_wcrt_mask(0x09, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80); if (info->var.vmode & FB_VMODE_INTERLACED) - svga_wcrt_mask(0x42, 0x20, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x42, 0x20, 0x20); else - svga_wcrt_mask(0x42, 0x00, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x42, 0x00, 0x20); /* Disable hardware graphics cursor */ - svga_wcrt_mask(0x45, 0x00, 0x01); + svga_wcrt_mask(par->state.vgabase, 0x45, 0x00, 0x01); /* Disable Streams engine */ - svga_wcrt_mask(0x67, 0x00, 0x0C); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0x0C); mode = svga_match_format(s3fb_formats, &(info->var), &(info->fix)); /* S3 virge DX hack */ if (par->chip == CHIP_375_VIRGE_DX) { - vga_wcrt(NULL, 0x86, 0x80); - vga_wcrt(NULL, 0x90, 0x00); + vga_wcrt(par->state.vgabase, 0x86, 0x80); + vga_wcrt(par->state.vgabase, 0x90, 0x00); } /* S3 virge VX hack */ if (par->chip == CHIP_988_VIRGE_VX) { - vga_wcrt(NULL, 0x50, 0x00); - vga_wcrt(NULL, 0x67, 0x50); + vga_wcrt(par->state.vgabase, 0x50, 0x00); + vga_wcrt(par->state.vgabase, 0x67, 0x50); - vga_wcrt(NULL, 0x63, (mode <= 2) ? 0x90 : 0x09); - vga_wcrt(NULL, 0x66, 0x90); + vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09); + vga_wcrt(par->state.vgabase, 0x66, 0x90); } if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || - par->chip == CHIP_368_TRIO3D_2X) { + par->chip == CHIP_368_TRIO3D_2X || + par->chip == CHIP_365_TRIO3D || + par->chip == CHIP_375_VIRGE_DX || + par->chip == CHIP_385_VIRGE_GX) { dbytes = info->var.xres * ((bpp+7)/8); - vga_wcrt(NULL, 0x91, (dbytes + 7) / 8); - vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); + vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8); + vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); - vga_wcrt(NULL, 0x66, 0x81); + vga_wcrt(par->state.vgabase, 0x66, 0x81); } - svga_wcrt_mask(0x31, 0x00, 0x40); + if (par->chip == CHIP_356_VIRGE_GX2 || + par->chip == CHIP_357_VIRGE_GX2P || + par->chip == CHIP_359_VIRGE_GX2P || + par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) + vga_wcrt(par->state.vgabase, 0x34, 0x00); + else /* enable Data Transfer Position Control (DTPC) */ + vga_wcrt(par->state.vgabase, 0x34, 0x10); + + svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40); multiplex = 0; hmul = 1; @@ -604,51 +635,51 @@ static int s3fb_set_par(struct fb_info *info) switch (mode) { case 0: pr_debug("fb%d: text mode\n", info->node); - svga_set_textmode_vga_regs(); + svga_set_textmode_vga_regs(par->state.vgabase); /* Set additional registers like in 8-bit mode */ - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); /* Disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); if (fasttext) { pr_debug("fb%d: high speed text mode set\n", info->node); - svga_wcrt_mask(0x31, 0x40, 0x40); + svga_wcrt_mask(par->state.vgabase, 0x31, 0x40, 0x40); } break; case 1: pr_debug("fb%d: 4 bit pseudocolor\n", info->node); - vga_wgfx(NULL, VGA_GFX_MODE, 0x40); + vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); /* Set additional registers like in 8-bit mode */ - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); /* disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); break; case 2: pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); /* Set additional registers like in 8-bit mode */ - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); /* disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); - svga_wcrt_mask(0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); if (info->var.pixclock > 20000 || par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X) - svga_wcrt_mask(0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); else { - svga_wcrt_mask(0x67, 0x10, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x10, 0xF0); multiplex = 1; } break; @@ -656,12 +687,21 @@ static int s3fb_set_par(struct fb_info *info) pr_debug("fb%d: 5/5/5 truecolor\n", info->node); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) - svga_wcrt_mask(0x67, 0x20, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0); else - svga_wcrt_mask(0x67, 0x30, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); + } else if (par->chip == CHIP_365_TRIO3D) { + svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); + if (info->var.pixclock > 8695) { + svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); + hmul = 2; + } else { + svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0); + multiplex = 1; + } } else { - svga_wcrt_mask(0x50, 0x10, 0x30); - svga_wcrt_mask(0x67, 0x30, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); if (par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) @@ -672,12 +712,21 @@ static int s3fb_set_par(struct fb_info *info) pr_debug("fb%d: 5/6/5 truecolor\n", info->node); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) - svga_wcrt_mask(0x67, 0x40, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0); else - svga_wcrt_mask(0x67, 0x50, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); + } else if (par->chip == CHIP_365_TRIO3D) { + svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); + if (info->var.pixclock > 8695) { + svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); + hmul = 2; + } else { + svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0); + multiplex = 1; + } } else { - svga_wcrt_mask(0x50, 0x10, 0x30); - svga_wcrt_mask(0x67, 0x50, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); if (par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) @@ -687,12 +736,12 @@ static int s3fb_set_par(struct fb_info *info) case 6: /* VIRGE VX case */ pr_debug("fb%d: 8/8/8 truecolor\n", info->node); - svga_wcrt_mask(0x67, 0xD0, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0); break; case 7: pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); - svga_wcrt_mask(0x50, 0x30, 0x30); - svga_wcrt_mask(0x67, 0xD0, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x30, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0); break; default: printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node); @@ -700,25 +749,30 @@ static int s3fb_set_par(struct fb_info *info) } if (par->chip != CHIP_988_VIRGE_VX) { - svga_wseq_mask(0x15, multiplex ? 0x10 : 0x00, 0x10); - svga_wseq_mask(0x18, multiplex ? 0x80 : 0x00, 0x80); + svga_wseq_mask(par->state.vgabase, 0x15, multiplex ? 0x10 : 0x00, 0x10); + svga_wseq_mask(par->state.vgabase, 0x18, multiplex ? 0x80 : 0x00, 0x80); } s3_set_pixclock(info, info->var.pixclock); - svga_set_timings(&s3_timing_regs, &(info->var), hmul, 1, + svga_set_timings(par->state.vgabase, &s3_timing_regs, &(info->var), hmul, 1, (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) / 8) - 5; - vga_wcrt(NULL, 0x3C, (value + 1) / 2); + htotal = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; + htotal = ((htotal * hmul) / 8) - 5; + vga_wcrt(par->state.vgabase, 0x3C, (htotal + 1) / 2); + + /* Set Data Transfer Position */ + hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8; + value = clamp((htotal + hsstart + 1) / 2, hsstart + 4, htotal + 1); + svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value); 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); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80); + svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); return 0; } @@ -788,31 +842,33 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int s3fb_blank(int blank_mode, struct fb_info *info) { + struct s3fb_info *par = info->par; + switch (blank_mode) { case FB_BLANK_UNBLANK: pr_debug("fb%d: unblank\n", info->node); - svga_wcrt_mask(0x56, 0x00, 0x06); - svga_wseq_mask(0x01, 0x00, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06); + svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); break; case FB_BLANK_NORMAL: pr_debug("fb%d: blank\n", info->node); - svga_wcrt_mask(0x56, 0x00, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_HSYNC_SUSPEND: pr_debug("fb%d: hsync\n", info->node); - svga_wcrt_mask(0x56, 0x02, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x02, 0x06); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_VSYNC_SUSPEND: pr_debug("fb%d: vsync\n", info->node); - svga_wcrt_mask(0x56, 0x04, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x04, 0x06); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_POWERDOWN: pr_debug("fb%d: sync down\n", info->node); - svga_wcrt_mask(0x56, 0x06, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x06, 0x06); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; } @@ -822,8 +878,9 @@ static int s3fb_blank(int blank_mode, struct fb_info *info) /* Pan the display */ -static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - +static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct s3fb_info *par = info->par; unsigned int offset; /* Calculate the offset */ @@ -837,7 +894,7 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) } /* Set the offset */ - svga_wcrt_multi(s3_start_address_regs, offset); + svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, offset); return 0; } @@ -863,12 +920,14 @@ static struct fb_ops s3fb_ops = { /* ------------------------------------------------------------------------- */ -static int __devinit s3_identification(int chip) +static int __devinit s3_identification(struct s3fb_info *par) { + int chip = par->chip; + if (chip == CHIP_XXX_TRIO) { - u8 cr30 = vga_rcrt(NULL, 0x30); - u8 cr2e = vga_rcrt(NULL, 0x2e); - u8 cr2f = vga_rcrt(NULL, 0x2f); + u8 cr30 = vga_rcrt(par->state.vgabase, 0x30); + u8 cr2e = vga_rcrt(par->state.vgabase, 0x2e); + u8 cr2f = vga_rcrt(par->state.vgabase, 0x2f); if ((cr30 == 0xE0) || (cr30 == 0xE1)) { if (cr2e == 0x10) @@ -883,7 +942,7 @@ static int __devinit s3_identification(int chip) } if (chip == CHIP_XXX_TRIO64V2_DXGX) { - u8 cr6f = vga_rcrt(NULL, 0x6f); + u8 cr6f = vga_rcrt(par->state.vgabase, 0x6f); if (! (cr6f & 0x01)) return CHIP_775_TRIO64V2_DX; @@ -892,7 +951,7 @@ static int __devinit s3_identification(int chip) } if (chip == CHIP_XXX_VIRGE_DXGX) { - u8 cr6f = vga_rcrt(NULL, 0x6f); + u8 cr6f = vga_rcrt(par->state.vgabase, 0x6f); if (! (cr6f & 0x01)) return CHIP_375_VIRGE_DX; @@ -901,7 +960,7 @@ static int __devinit s3_identification(int chip) } if (chip == CHIP_36X_TRIO3D_1X_2X) { - switch (vga_rcrt(NULL, 0x2f)) { + switch (vga_rcrt(par->state.vgabase, 0x2f)) { case 0x00: return CHIP_360_TRIO3D_1X; case 0x01: @@ -919,6 +978,8 @@ static int __devinit s3_identification(int chip) static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { + struct pci_bus_region bus_reg; + struct resource vga_res; struct fb_info *info; struct s3fb_info *par; int rc; @@ -968,31 +1029,42 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i goto err_iomap; } + bus_reg.start = 0; + bus_reg.end = 64 * 1024; + + vga_res.flags = IORESOURCE_IO; + + pcibios_bus_to_resource(dev, &vga_res, &bus_reg); + + par->state.vgabase = (void __iomem *) vga_res.start; + /* Unlock regs */ - cr38 = vga_rcrt(NULL, 0x38); - cr39 = vga_rcrt(NULL, 0x39); - vga_wseq(NULL, 0x08, 0x06); - vga_wcrt(NULL, 0x38, 0x48); - vga_wcrt(NULL, 0x39, 0xA5); + cr38 = vga_rcrt(par->state.vgabase, 0x38); + cr39 = vga_rcrt(par->state.vgabase, 0x39); + vga_wseq(par->state.vgabase, 0x08, 0x06); + vga_wcrt(par->state.vgabase, 0x38, 0x48); + vga_wcrt(par->state.vgabase, 0x39, 0xA5); /* Identify chip type */ par->chip = id->driver_data & CHIP_MASK; - par->rev = vga_rcrt(NULL, 0x2f); + par->rev = vga_rcrt(par->state.vgabase, 0x2f); if (par->chip & CHIP_UNDECIDED_FLAG) - par->chip = s3_identification(par->chip); + par->chip = s3_identification(par); /* Find how many physical memory there is on card */ /* 0x36 register is accessible even if other registers are locked */ - regval = vga_rcrt(NULL, 0x36); + regval = vga_rcrt(par->state.vgabase, 0x36); if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || - par->chip == CHIP_368_TRIO3D_2X) { + par->chip == CHIP_368_TRIO3D_2X || + par->chip == CHIP_365_TRIO3D) { switch ((regval & 0xE0) >> 5) { case 0: /* 8MB -- only 4MB usable for display */ case 1: /* 4MB with 32-bit bus */ case 2: /* 4MB */ info->screen_size = 4 << 20; break; + case 4: /* 2MB on 365 Trio3D */ case 6: /* 2MB */ info->screen_size = 2 << 20; break; @@ -1002,13 +1074,13 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->fix.smem_len = info->screen_size; /* Find MCLK frequency */ - regval = vga_rseq(NULL, 0x10); - par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2); + regval = vga_rseq(par->state.vgabase, 0x10); + par->mclk_freq = ((vga_rseq(par->state.vgabase, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2); par->mclk_freq = par->mclk_freq >> (regval >> 5); /* Restore locks */ - vga_wcrt(NULL, 0x38, cr38); - vga_wcrt(NULL, 0x39, cr39); + vga_wcrt(par->state.vgabase, 0x38, cr38); + vga_wcrt(par->state.vgabase, 0x39, cr39); strcpy(info->fix.id, s3_names [par->chip]); info->fix.mmio_start = 0; @@ -1027,6 +1099,14 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i goto err_find_mode; } + /* 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 (info->var.yres_virtual < info->var.yres) { + dev_err(info->device, "virtual vertical size smaller than real\n"); + goto err_find_mode; + } + rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { dev_err(info->device, "cannot allocate colormap\n"); @@ -1044,8 +1124,8 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i if (par->chip == CHIP_UNKNOWN) printk(KERN_INFO "fb%d: unknown chip, CR2D=%x, CR2E=%x, CRT2F=%x, CRT30=%x\n", - info->node, vga_rcrt(NULL, 0x2d), vga_rcrt(NULL, 0x2e), - vga_rcrt(NULL, 0x2f), vga_rcrt(NULL, 0x30)); + info->node, vga_rcrt(par->state.vgabase, 0x2d), vga_rcrt(par->state.vgabase, 0x2e), + vga_rcrt(par->state.vgabase, 0x2f), vga_rcrt(par->state.vgabase, 0x30)); /* Record a reference to the driver data */ pci_set_drvdata(dev, info); @@ -1113,12 +1193,12 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) dev_info(info->device, "suspend\n"); - acquire_console_sem(); + console_lock(); mutex_lock(&(par->open_lock)); if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) { mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1129,7 +1209,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state) pci_set_power_state(dev, pci_choose_state(dev, state)); mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1145,12 +1225,12 @@ static int s3_pci_resume(struct pci_dev* dev) dev_info(info->device, "resume\n"); - acquire_console_sem(); + console_lock(); mutex_lock(&(par->open_lock)); if (par->ref_count == 0) { mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1159,7 +1239,7 @@ static int s3_pci_resume(struct pci_dev* dev) err = pci_enable_device(dev); if (err) { mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); dev_err(info->device, "error %d enabling device for resume\n", err); return err; } @@ -1169,7 +1249,7 @@ static int s3_pci_resume(struct pci_dev* dev) fb_set_suspend(info, 0); mutex_unlock(&(par->open_lock)); - release_console_sem(); + console_unlock(); return 0; } @@ -1192,6 +1272,7 @@ static struct pci_device_id s3_devices[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D}, {0, 0, 0, 0, 0, 0, 0} }; |