diff options
Diffstat (limited to 'drivers/video')
66 files changed, 16492 insertions, 1150 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index f79c2040758..0f13448c6f7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -76,6 +76,14 @@ config FB_DDC select I2C default n +config FB_BOOT_VESA_SUPPORT + bool + depends on FB + default n + ---help--- + If true, at least one selected framebuffer driver can take advantage + of VESA video modes set at an early boot stage via the vga= parameter. + config FB_CFB_FILLRECT tristate depends on FB @@ -254,16 +262,24 @@ config FB_PM2 select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT help - This is the frame buffer device driver for the Permedia2 AGP frame - buffer card from ASK, aka `Graphic Blaster Exxtreme'. There is a - product page at - <http://www.ask.com.hk/product/Permedia%202/permedia2.htm>. + This is the frame buffer device driver for cards based on + the 3D Labs Permedia, Permedia 2 and Permedia 2V chips. + The driver was tested on the following cards: + Diamond FireGL 1000 PRO AGP + ELSA Gloria Synergy PCI + Appian Jeronimo PRO (both heads) PCI + 3DLabs Oxygen ACX aka EONtronics Picasso P2 PCI + Techsource Raptor GFX-8P (aka Sun PGX-32) on SPARC + ASK Graphic Blaster Exxtreme AGP + + To compile this driver as a module, choose M here: the + module will be called pm2fb. config FB_PM2_FIFO_DISCONNECT bool "enable FIFO disconnect feature" depends on FB_PM2 && PCI help - Support the Permedia2 FIFO disconnect feature (see CONFIG_FB_PM2). + Support the Permedia2 FIFO disconnect feature. config FB_ARMCLCD tristate "ARM PrimeCell PL110 support" @@ -673,6 +689,7 @@ config FB_VESA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select FB_BOOT_VESA_SUPPORT help This is the frame buffer device driver for generic VESA 2.0 compliant graphic cards. The older VESA 1.2 cards are not supported. @@ -681,23 +698,14 @@ config FB_VESA config FB_EFI bool "EFI-based Framebuffer Support" - depends on (FB = y) && X86 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the EFI frame buffer device driver. If the firmware on - your platform is UEFI2.0, select Y to add support for - Graphics Output Protocol for early console messages to appear. - -config FB_IMAC - bool "Intel-based Macintosh Framebuffer Support" depends on (FB = y) && X86 && EFI select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT help - This is the frame buffer device driver for the Intel-based Macintosh + This is the EFI frame buffer device driver. If the firmware on + your platform is EFI 1.10 or UEFI 2.0, select Y to add support for + using the EFI framebuffer as your console. config FB_N411 tristate "N411 Apollo/Hecuba devkit support" @@ -1118,6 +1126,7 @@ config FB_INTEL select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select FB_BOOT_VESA_SUPPORT help This driver supports the on-board graphics built in to the Intel 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets. @@ -1470,6 +1479,7 @@ config FB_SIS select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select FB_BOOT_VESA_SUPPORT help This is the frame buffer device driver for the SiS 300, 315, 330 and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. @@ -1492,6 +1502,24 @@ config FB_SIS_315 (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760, 761) as well as XGI V3XT, V5, V8 and Z7. +config FB_VIA + tristate "VIA UniChrome (Pro) and Chrome9 display support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR + select I2C_ALGOBIT + select I2C + help + This is the frame buffer device driver for Graphics chips of VIA + UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ + CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896 + /P4M900,VX800) + Say Y if you have a VIA UniChrome graphics board. + + To compile this driver as a module, choose M here: the + module will be called viafb. config FB_NEOMAGIC tristate "NeoMagic display support" depends on FB && PCI @@ -1521,25 +1549,25 @@ config FB_KYRO module will be called kyrofb. config FB_3DFX - tristate "3Dfx Banshee/Voodoo3 display support" + tristate "3Dfx Banshee/Voodoo3/Voodoo5 display support" depends on FB && PCI select FB_CFB_IMAGEBLIT select FB_CFB_FILLRECT select FB_CFB_COPYAREA help - This driver supports graphics boards with the 3Dfx Banshee/Voodoo3 - chips. Say Y if you have such a graphics board. + This driver supports graphics boards with the 3Dfx Banshee, + Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have + such a graphics board. To compile this driver as a module, choose M here: the module will be called tdfxfb. config FB_3DFX_ACCEL - bool "3Dfx Banshee/Voodoo3 Acceleration functions (EXPERIMENTAL)" + bool "3Dfx Acceleration functions (EXPERIMENTAL)" depends on FB_3DFX && EXPERIMENTAL ---help--- - This will compile the 3Dfx Banshee/Voodoo3 frame buffer device - with acceleration functions. - + This will compile the 3Dfx Banshee/Voodoo3/VSA-100 frame buffer + device driver with acceleration functions. config FB_VOODOO1 tristate "3Dfx Voodoo Graphics (sst1) support" @@ -1604,17 +1632,16 @@ config FB_TRIDENT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT ---help--- - This driver is supposed to support graphics boards with the - Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops + This is the frame buffer device driver for Trident PCI/AGP chipsets. + Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D + and Blade XP. + There are also integrated versions of these chips called CyberXXXX, + CyberImage or CyberBlade. These chips are mostly found in laptops but also on some motherboards. For more information, read <file:Documentation/fb/tridentfb.txt> - Cyberblade/i1 support will be removed soon, use the cyblafb driver - instead. - Say Y if you have such a graphics board. - To compile this driver as a module, choose M here: the module will be called tridentfb. @@ -1869,6 +1896,28 @@ config FB_SH_MOBILE_LCDC ---help--- Frame buffer driver for the on-chip SH-Mobile LCD controller. +config FB_TMIO + tristate "Toshiba Mobile IO FrameBuffer support" + depends on FB && MFD_CORE + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Frame buffer driver for the Toshiba Mobile IO integrated as found + on the Sharp SL-6000 series + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called tmiofb. If you want to compile it as a module, + say M here and read <file:Documentation/kbuild/modules.txt>. + + If unsure, say N. + +config FB_TMIO_ACCELL + bool "tmiofb acceleration" + depends on FB_TMIO + default y + config FB_S3C2410 tristate "S3C2410 LCD framebuffer support" depends on FB && ARCH_S3C2410 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index ad0330bf9be..248bddc8d0b 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_FB_ATY) += aty/ macmodes.o obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o obj-$(CONFIG_FB_RADEON) += aty/ obj-$(CONFIG_FB_SIS) += sis/ +obj-$(CONFIG_FB_VIA) += via/ obj-$(CONFIG_FB_KYRO) += kyro/ obj-$(CONFIG_FB_SAVAGE) += savage/ obj-$(CONFIG_FB_GEODE) += geode/ @@ -97,6 +98,7 @@ obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o obj-$(CONFIG_FB_PXA) += pxafb.o obj-$(CONFIG_FB_W100) += w100fb.o +obj-$(CONFIG_FB_TMIO) += tmiofb.o obj-$(CONFIG_FB_AU1100) += au1100fb.o obj-$(CONFIG_FB_AU1200) += au1200fb.o obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o @@ -124,7 +126,6 @@ obj-$(CONFIG_FB_CARMINE) += carminefb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o obj-$(CONFIG_FB_VESA) += vesafb.o -obj-$(CONFIG_FB_IMAC) += imacfb.o obj-$(CONFIG_FB_EFI) += efifb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index d38fd521742..f8d0a57a07c 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -372,6 +372,13 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, var->transp.offset = var->transp.length = 0; var->xoffset = var->yoffset = 0; + if (info->fix.smem_len) { + unsigned int smem_len = (var->xres_virtual * var->yres_virtual + * ((var->bits_per_pixel + 7) / 8)); + if (smem_len > info->fix.smem_len) + return -EINVAL; + } + /* Saturate vertical and horizontal timings at maximum values */ var->vsync_len = min_t(u32, var->vsync_len, (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c index aa95f835024..8718f7349d6 100644 --- a/drivers/video/aty/radeon_accel.c +++ b/drivers/video/aty/radeon_accel.c @@ -5,61 +5,61 @@ * --dte */ -static void radeon_fixup_offset(struct radeonfb_info *rinfo) +#define FLUSH_CACHE_WORKAROUND 1 + +void radeon_fifo_update_and_wait(struct radeonfb_info *rinfo, int entries) { - u32 local_base; - - /* *** Ugly workaround *** */ - /* - * On some platforms, the video memory is mapped at 0 in radeon chip space - * (like PPCs) by the firmware. X will always move it up so that it's seen - * by the chip to be at the same address as the PCI BAR. - * That means that when switching back from X, there is a mismatch between - * the offsets programmed into the engine. This means that potentially, - * accel operations done before radeonfb has a chance to re-init the engine - * will have incorrect offsets, and potentially trash system memory ! - * - * The correct fix is for fbcon to never call any accel op before the engine - * has properly been re-initialized (by a call to set_var), but this is a - * complex fix. This workaround in the meantime, called before every accel - * operation, makes sure the offsets are in sync. - */ + int i; - radeon_fifo_wait (1); - local_base = INREG(MC_FB_LOCATION) << 16; - if (local_base == rinfo->fb_local_base) - return; + for (i=0; i<2000000; i++) { + rinfo->fifo_free = INREG(RBBM_STATUS) & 0x7f; + if (rinfo->fifo_free >= entries) + return; + udelay(10); + } + printk(KERN_ERR "radeonfb: FIFO Timeout !\n"); + /* XXX Todo: attempt to reset the engine */ +} - rinfo->fb_local_base = local_base; +static inline void radeon_fifo_wait(struct radeonfb_info *rinfo, int entries) +{ + if (entries <= rinfo->fifo_free) + rinfo->fifo_free -= entries; + else + radeon_fifo_update_and_wait(rinfo, entries); +} - radeon_fifo_wait (3); - OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) | - (rinfo->fb_local_base >> 10)); - OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10)); - OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10)); +static inline void radeonfb_set_creg(struct radeonfb_info *rinfo, u32 reg, + u32 *cache, u32 new_val) +{ + if (new_val == *cache) + return; + *cache = new_val; + radeon_fifo_wait(rinfo, 1); + OUTREG(reg, new_val); } static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo, const struct fb_fillrect *region) { - radeon_fifo_wait(4); - - OUTREG(DP_GUI_MASTER_CNTL, - rinfo->dp_gui_master_cntl /* contains, like GMC_DST_32BPP */ - | GMC_BRUSH_SOLID_COLOR - | ROP3_P); - if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP) - OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]); - else - OUTREG(DP_BRUSH_FRGD_CLR, region->color); - OUTREG(DP_WRITE_MSK, 0xffffffff); - OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM)); - - radeon_fifo_wait(2); + radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache, + rinfo->dp_gui_mc_base | GMC_BRUSH_SOLID_COLOR | ROP3_P); + radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache, + DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); + radeonfb_set_creg(rinfo, DP_BRUSH_FRGD_CLR, &rinfo->dp_brush_fg_cache, + region->color); + + /* Ensure the dst cache is flushed and the engine idle before + * issuing the operation. + * + * This works around engine lockups on some cards + */ +#if FLUSH_CACHE_WORKAROUND + radeon_fifo_wait(rinfo, 2); OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL); OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE)); - - radeon_fifo_wait(2); +#endif + radeon_fifo_wait(rinfo, 2); OUTREG(DST_Y_X, (region->dy << 16) | region->dx); OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height); } @@ -70,15 +70,14 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region) struct fb_fillrect modded; int vxres, vyres; - if (info->state != FBINFO_STATE_RUNNING) + WARN_ON(rinfo->gfx_mode); + if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode) return; if (info->flags & FBINFO_HWACCEL_DISABLED) { cfb_fillrect(info, region); return; } - radeon_fixup_offset(rinfo); - vxres = info->var.xres_virtual; vyres = info->var.yres_virtual; @@ -91,6 +90,10 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region) if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx; if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy; + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR ) + modded.color = ((u32 *) (info->pseudo_palette))[region->color]; + radeonfb_prim_fillrect(rinfo, &modded); } @@ -109,22 +112,22 @@ static void radeonfb_prim_copyarea(struct radeonfb_info *rinfo, if ( xdir < 0 ) { sx += w-1; dx += w-1; } if ( ydir < 0 ) { sy += h-1; dy += h-1; } - radeon_fifo_wait(3); - OUTREG(DP_GUI_MASTER_CNTL, - rinfo->dp_gui_master_cntl /* i.e. GMC_DST_32BPP */ - | GMC_BRUSH_NONE - | GMC_SRC_DSTCOLOR - | ROP3_S - | DP_SRC_SOURCE_MEMORY ); - OUTREG(DP_WRITE_MSK, 0xffffffff); - OUTREG(DP_CNTL, (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0) - | (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0)); - - radeon_fifo_wait(2); + radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache, + rinfo->dp_gui_mc_base | + GMC_BRUSH_NONE | + GMC_SRC_DATATYPE_COLOR | + ROP3_S | + DP_SRC_SOURCE_MEMORY); + radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache, + (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0) | + (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0)); + +#if FLUSH_CACHE_WORKAROUND + radeon_fifo_wait(rinfo, 2); OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL); OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE)); - - radeon_fifo_wait(3); +#endif + radeon_fifo_wait(rinfo, 3); OUTREG(SRC_Y_X, (sy << 16) | sx); OUTREG(DST_Y_X, (dy << 16) | dx); OUTREG(DST_HEIGHT_WIDTH, (h << 16) | w); @@ -143,15 +146,14 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) modded.width = area->width; modded.height = area->height; - if (info->state != FBINFO_STATE_RUNNING) + WARN_ON(rinfo->gfx_mode); + if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode) return; if (info->flags & FBINFO_HWACCEL_DISABLED) { cfb_copyarea(info, area); return; } - radeon_fixup_offset(rinfo); - vxres = info->var.xres_virtual; vyres = info->var.yres_virtual; @@ -168,13 +170,112 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) radeonfb_prim_copyarea(rinfo, &modded); } +static void radeonfb_prim_imageblit(struct radeonfb_info *rinfo, + const struct fb_image *image, + u32 fg, u32 bg) +{ + unsigned int src_bytes, dwords; + u32 *bits; + + radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache, + rinfo->dp_gui_mc_base | + GMC_BRUSH_NONE | + GMC_SRC_DATATYPE_MONO_FG_BG | + ROP3_S | + GMC_BYTE_ORDER_MSB_TO_LSB | + DP_SRC_SOURCE_HOST_DATA); + radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache, + DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); + radeonfb_set_creg(rinfo, DP_SRC_FRGD_CLR, &rinfo->dp_src_fg_cache, fg); + radeonfb_set_creg(rinfo, DP_SRC_BKGD_CLR, &rinfo->dp_src_bg_cache, bg); + + radeon_fifo_wait(rinfo, 1); + OUTREG(DST_Y_X, (image->dy << 16) | image->dx); + + /* Ensure the dst cache is flushed and the engine idle before + * issuing the operation. + * + * This works around engine lockups on some cards + */ +#if FLUSH_CACHE_WORKAROUND + radeon_fifo_wait(rinfo, 2); + OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL); + OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE)); +#endif + + /* X here pads width to a multiple of 32 and uses the clipper to + * adjust the result. Is that really necessary ? Things seem to + * work ok for me without that and the doco doesn't seem to imply + * there is such a restriction. + */ + OUTREG(DST_WIDTH_HEIGHT, (image->width << 16) | image->height); + + src_bytes = (((image->width * image->depth) + 7) / 8) * image->height; + dwords = (src_bytes + 3) / 4; + bits = (u32*)(image->data); + + while(dwords >= 8) { + radeon_fifo_wait(rinfo, 8); +#if BITS_PER_LONG == 64 + __raw_writeq(*((u64 *)(bits)), rinfo->mmio_base + HOST_DATA0); + __raw_writeq(*((u64 *)(bits+2)), rinfo->mmio_base + HOST_DATA2); + __raw_writeq(*((u64 *)(bits+4)), rinfo->mmio_base + HOST_DATA4); + __raw_writeq(*((u64 *)(bits+6)), rinfo->mmio_base + HOST_DATA6); + bits += 8; +#else + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA0); + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA1); + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA2); + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA3); + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA4); + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA5); + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA6); + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA7); +#endif + dwords -= 8; + } + while(dwords--) { + radeon_fifo_wait(rinfo, 1); + __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA0); + } +} + void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image) { struct radeonfb_info *rinfo = info->par; + u32 fg, bg; - if (info->state != FBINFO_STATE_RUNNING) + WARN_ON(rinfo->gfx_mode); + if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode) + return; + + if (!image->width || !image->height) return; - radeon_engine_idle(); + + /* We only do 1 bpp color expansion for now */ + if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) + goto fallback; + + /* Fallback if running out of the screen. We may do clipping + * in the future */ + if ((image->dx + image->width) > info->var.xres_virtual || + (image->dy + image->height) > info->var.yres_virtual) + goto fallback; + + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fg = ((u32*)(info->pseudo_palette))[image->fg_color]; + bg = ((u32*)(info->pseudo_palette))[image->bg_color]; + } else { + fg = image->fg_color; + bg = image->bg_color; + } + + radeonfb_prim_imageblit(rinfo, image, fg, bg); + return; + + fallback: + radeon_engine_idle(rinfo); cfb_imageblit(info, image); } @@ -185,7 +286,8 @@ int radeonfb_sync(struct fb_info *info) if (info->state != FBINFO_STATE_RUNNING) return 0; - radeon_engine_idle(); + + radeon_engine_idle(rinfo); return 0; } @@ -211,9 +313,7 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo) host_path_cntl = INREG(HOST_PATH_CNTL); rbbm_soft_reset = INREG(RBBM_SOFT_RESET); - if (rinfo->family == CHIP_FAMILY_R300 || - rinfo->family == CHIP_FAMILY_R350 || - rinfo->family == CHIP_FAMILY_RV350) { + if (IS_R300_VARIANT(rinfo)) { u32 tmp; OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset | @@ -249,9 +349,7 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo) INREG(HOST_PATH_CNTL); OUTREG(HOST_PATH_CNTL, host_path_cntl); - if (rinfo->family != CHIP_FAMILY_R300 && - rinfo->family != CHIP_FAMILY_R350 && - rinfo->family != CHIP_FAMILY_RV350) + if (!IS_R300_VARIANT(rinfo)) OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset); OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index); @@ -265,15 +363,24 @@ void radeonfb_engine_init (struct radeonfb_info *rinfo) /* disable 3D engine */ OUTREG(RB3D_CNTL, 0); + rinfo->fifo_free = 0; radeonfb_engine_reset(rinfo); - radeon_fifo_wait (1); - if ((rinfo->family != CHIP_FAMILY_R300) && - (rinfo->family != CHIP_FAMILY_R350) && - (rinfo->family != CHIP_FAMILY_RV350)) + radeon_fifo_wait(rinfo, 1); + if (IS_R300_VARIANT(rinfo)) { + OUTREG(RB2D_DSTCACHE_MODE, INREG(RB2D_DSTCACHE_MODE) | + RB2D_DC_AUTOFLUSH_ENABLE | + RB2D_DC_DC_DISABLE_IGNORE_PE); + } else { + /* This needs to be double checked with ATI. Latest X driver + * completely "forgets" to set this register on < r3xx, and + * we used to just write 0 there... I'll keep the 0 and update + * that when we have sorted things out on X side. + */ OUTREG(RB2D_DSTCACHE_MODE, 0); + } - radeon_fifo_wait (3); + radeon_fifo_wait(rinfo, 3); /* We re-read MC_FB_LOCATION from card as it can have been * modified by XFree drivers (ouch !) */ @@ -284,41 +391,57 @@ void radeonfb_engine_init (struct radeonfb_info *rinfo) OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10)); OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10)); - radeon_fifo_wait (1); -#if defined(__BIG_ENDIAN) + radeon_fifo_wait(rinfo, 1); +#ifdef __BIG_ENDIAN OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN); #else OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN); #endif - radeon_fifo_wait (2); + radeon_fifo_wait(rinfo, 2); OUTREG(DEFAULT_SC_TOP_LEFT, 0); OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX | DEFAULT_SC_BOTTOM_MAX)); + /* set default DP_GUI_MASTER_CNTL */ temp = radeon_get_dstbpp(rinfo->depth); - rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS); + rinfo->dp_gui_mc_base = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS); - radeon_fifo_wait (1); - OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | - GMC_BRUSH_SOLID_COLOR | - GMC_SRC_DATATYPE_COLOR)); + rinfo->dp_gui_mc_cache = rinfo->dp_gui_mc_base | + GMC_BRUSH_SOLID_COLOR | + GMC_SRC_DATATYPE_COLOR; + radeon_fifo_wait(rinfo, 1); + OUTREG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_mc_cache); - radeon_fifo_wait (7); /* clear line drawing regs */ + radeon_fifo_wait(rinfo, 2); OUTREG(DST_LINE_START, 0); OUTREG(DST_LINE_END, 0); - /* set brush color regs */ - OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff); - OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000); - - /* set source color regs */ - OUTREG(DP_SRC_FRGD_CLR, 0xffffffff); - OUTREG(DP_SRC_BKGD_CLR, 0x00000000); + /* set brush and source color regs */ + rinfo->dp_brush_fg_cache = 0xffffffff; + rinfo->dp_brush_bg_cache = 0x00000000; + rinfo->dp_src_fg_cache = 0xffffffff; + rinfo->dp_src_bg_cache = 0x00000000; + radeon_fifo_wait(rinfo, 4); + OUTREG(DP_BRUSH_FRGD_CLR, rinfo->dp_brush_fg_cache); + OUTREG(DP_BRUSH_BKGD_CLR, rinfo->dp_brush_bg_cache); + OUTREG(DP_SRC_FRGD_CLR, rinfo->dp_src_fg_cache); + OUTREG(DP_SRC_BKGD_CLR, rinfo->dp_src_bg_cache); + + /* Default direction */ + rinfo->dp_cntl_cache = DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM; + radeon_fifo_wait(rinfo, 1); + OUTREG(DP_CNTL, rinfo->dp_cntl_cache); /* default write mask */ + radeon_fifo_wait(rinfo, 1); OUTREG(DP_WRITE_MSK, 0xffffffff); - radeon_engine_idle (); + /* Default to no swapping of host data */ + radeon_fifo_wait(rinfo, 1); + OUTREG(RBBM_GUICNTL, RBBM_GUICNTL_HOST_DATA_SWAP_NONE); + + /* Make sure it's settled */ + radeon_engine_idle(rinfo); } diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 1a056adb61c..f343ba83f0a 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -66,7 +66,7 @@ static int radeon_bl_update_status(struct backlight_device *bd) level = bd->props.brightness; del_timer_sync(&rinfo->lvds_timer); - radeon_engine_idle(); + radeon_engine_idle(rinfo); lvds_gen_cntl = INREG(LVDS_GEN_CNTL); if (level > 0) { diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 652273e9f5f..9a5821c65eb 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -852,7 +852,6 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var, if (rinfo->asleep) return 0; - radeon_fifo_wait(2); OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel / 8) & ~7); return 0; @@ -882,7 +881,6 @@ static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd, if (rc) return rc; - radeon_fifo_wait(2); if (value & 0x01) { tmp = INREG(LVDS_GEN_CNTL); @@ -940,7 +938,7 @@ int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch) if (rinfo->lock_blank) return 0; - radeon_engine_idle(); + radeon_engine_idle(rinfo); val = INREG(CRTC_EXT_CNTL); val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | @@ -1048,7 +1046,7 @@ static int radeonfb_blank (int blank, struct fb_info *info) if (rinfo->asleep) return 0; - + return radeon_screen_blank(rinfo, blank, 0); } @@ -1074,8 +1072,6 @@ static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, pindex = regno; if (!rinfo->asleep) { - radeon_fifo_wait(9); - if (rinfo->bpp == 16) { pindex = regno * 8; @@ -1244,8 +1240,6 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg { int i; - radeon_fifo_wait(20); - /* Workaround from XFree */ if (rinfo->is_mobility) { /* A temporal workaround for the occational blanking on certain laptop @@ -1286,11 +1280,10 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg radeon_pll_errata_after_data(rinfo); /* Set PPLL ref. div */ - if (rinfo->family == CHIP_FAMILY_R300 || + if (IS_R300_VARIANT(rinfo) || rinfo->family == CHIP_FAMILY_RS300 || - rinfo->family == CHIP_FAMILY_R350 || - rinfo->family == CHIP_FAMILY_RV350 || - rinfo->family == CHIP_FAMILY_RV380 ) { + rinfo->family == CHIP_FAMILY_RS400 || + rinfo->family == CHIP_FAMILY_RS480) { if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { /* When restoring console mode, use saved PPLL_REF_DIV * setting. @@ -1342,7 +1335,7 @@ static void radeon_lvds_timer_func(unsigned long data) { struct radeonfb_info *rinfo = (struct radeonfb_info *)data; - radeon_engine_idle(); + radeon_engine_idle(rinfo); OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl); } @@ -1360,10 +1353,11 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, if (nomodeset) return; + radeon_engine_idle(rinfo); + if (!regs_only) radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0); - radeon_fifo_wait(31); for (i=0; i<10; i++) OUTREG(common_regs[i].reg, common_regs[i].val); @@ -1391,7 +1385,6 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, radeon_write_pll_regs(rinfo, mode); if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { - radeon_fifo_wait(10); OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp); OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp); OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid); @@ -1406,7 +1399,6 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, if (!regs_only) radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0); - radeon_fifo_wait(2); OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl); return; @@ -1461,10 +1453,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs /* Not all chip revs have the same format for this register, * extract the source selection */ - if (rinfo->family == CHIP_FAMILY_R200 || - rinfo->family == CHIP_FAMILY_R300 || - rinfo->family == CHIP_FAMILY_R350 || - rinfo->family == CHIP_FAMILY_RV350) { + if (rinfo->family == CHIP_FAMILY_R200 || IS_R300_VARIANT(rinfo)) { source = (fp2_gen_cntl >> 10) & 0x3; /* sourced from transform unit, check for transform unit * own source @@ -1560,7 +1549,7 @@ static int radeonfb_set_par(struct fb_info *info) /* We always want engine to be idle on a mode switch, even * if we won't actually change the mode */ - radeon_engine_idle(); + radeon_engine_idle(rinfo); hSyncStart = mode->xres + mode->right_margin; hSyncEnd = hSyncStart + mode->hsync_len; @@ -1855,7 +1844,6 @@ static int radeonfb_set_par(struct fb_info *info) return 0; } - static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, .fb_check_var = radeonfb_check_var, @@ -1879,6 +1867,7 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) info->par = rinfo; info->pseudo_palette = rinfo->pseudo_palette; info->flags = FBINFO_DEFAULT + | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_XPAN @@ -2005,11 +1994,11 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo) (rinfo->family == CHIP_FAMILY_RS200) || (rinfo->family == CHIP_FAMILY_RS300) || (rinfo->family == CHIP_FAMILY_RC410) || + (rinfo->family == CHIP_FAMILY_RS400) || (rinfo->family == CHIP_FAMILY_RS480) ) { u32 tom = INREG(NB_TOM); tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024); - radeon_fifo_wait(6); OUTREG(MC_FB_LOCATION, tom); OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16); OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16); diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index 8c8fa35f1b7..2c5567175dc 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -139,12 +139,8 @@ void radeon_delete_i2c_busses(struct radeonfb_info *rinfo) int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid) { - u32 reg = rinfo->i2c[conn-1].ddc_reg; u8 *edid; - OUTREG(reg, INREG(reg) & - ~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT)); - edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter); if (out_edid) diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index 675abdafc2d..3df5015f1d1 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -2653,9 +2653,9 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) if (!(info->flags & FBINFO_HWACCEL_DISABLED)) { /* Make sure engine is reset */ - radeon_engine_idle(); + radeon_engine_idle(rinfo); radeonfb_engine_reset(rinfo); - radeon_engine_idle(); + radeon_engine_idle(rinfo); } /* Blank display and LCD */ @@ -2767,7 +2767,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev) rinfo->asleep = 0; } else - radeon_engine_idle(); + radeon_engine_idle(rinfo); /* Restore display & engine */ radeon_write_mode (rinfo, &rinfo->state, 1); diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index ccbfffd1280..ea0b5b47aca 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -53,6 +53,7 @@ enum radeon_family { CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */ CHIP_FAMILY_R420, /* R420/R423/M18 */ CHIP_FAMILY_RC410, + CHIP_FAMILY_RS400, CHIP_FAMILY_RS480, CHIP_FAMILY_LAST, }; @@ -335,7 +336,15 @@ struct radeonfb_info { int mon2_type; u8 *mon2_EDID; - u32 dp_gui_master_cntl; + /* accel bits */ + u32 dp_gui_mc_base; + u32 dp_gui_mc_cache; + u32 dp_cntl_cache; + u32 dp_brush_fg_cache; + u32 dp_brush_bg_cache; + u32 dp_src_fg_cache; + u32 dp_src_bg_cache; + u32 fifo_free; struct pll_info pll; @@ -347,6 +356,7 @@ struct radeonfb_info { int lock_blank; int dynclk; int no_schedule; + int gfx_mode; enum radeon_pm_mode pm_mode; reinit_function_ptr reinit_func; @@ -391,8 +401,14 @@ static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms) #define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr) #define INREG16(addr) readw((rinfo->mmio_base)+addr) #define OUTREG16(addr,val) writew(val, (rinfo->mmio_base)+addr) + +#ifdef CONFIG_PPC +#define INREG(addr) ({ eieio(); ld_le32(rinfo->mmio_base+(addr)); }) +#define OUTREG(addr,val) do { eieio(); st_le32(rinfo->mmio_base+(addr),(val)); } while(0) +#else #define INREG(addr) readl((rinfo->mmio_base)+addr) #define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr) +#endif static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr, u32 val, u32 mask) @@ -533,16 +549,25 @@ static inline u32 radeon_get_dstbpp(u16 depth) /* * 2D Engine helper routines */ + +extern void radeon_fifo_update_and_wait(struct radeonfb_info *rinfo, int entries); + static inline void radeon_engine_flush (struct radeonfb_info *rinfo) { int i; - /* initiate flush */ - OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL, + /* Initiate flush */ + OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL, ~RB2D_DC_FLUSH_ALL); + /* Ensure FIFO is empty, ie, make sure the flush commands + * has reached the cache + */ + radeon_fifo_update_and_wait(rinfo, 64); + + /* Wait for the flush to complete */ for (i=0; i < 2000000; i++) { - if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY)) + if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY)) return; udelay(1); } @@ -550,25 +575,12 @@ static inline void radeon_engine_flush (struct radeonfb_info *rinfo) } -static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries) -{ - int i; - - for (i=0; i<2000000; i++) { - if ((INREG(RBBM_STATUS) & 0x7f) >= entries) - return; - udelay(1); - } - printk(KERN_ERR "radeonfb: FIFO Timeout !\n"); -} - - -static inline void _radeon_engine_idle(struct radeonfb_info *rinfo) +static inline void radeon_engine_idle(struct radeonfb_info *rinfo) { int i; /* ensure FIFO is empty before waiting for idle */ - _radeon_fifo_wait (rinfo, 64); + radeon_fifo_update_and_wait (rinfo, 64); for (i=0; i<2000000; i++) { if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) { @@ -581,8 +593,6 @@ static inline void _radeon_engine_idle(struct radeonfb_info *rinfo) } -#define radeon_engine_idle() _radeon_engine_idle(rinfo) -#define radeon_fifo_wait(entries) _radeon_fifo_wait(rinfo,entries) #define radeon_msleep(ms) _radeon_msleep(rinfo,ms) @@ -612,6 +622,7 @@ extern void radeonfb_imageblit(struct fb_info *p, const struct fb_image *image); extern int radeonfb_sync(struct fb_info *info); extern void radeonfb_engine_init (struct radeonfb_info *rinfo); extern void radeonfb_engine_reset(struct radeonfb_info *rinfo); +extern void radeon_fixup_mem_offset(struct radeonfb_info *rinfo); /* Other functions */ extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch); diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index e15bb447440..c9b191319a9 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -535,7 +535,7 @@ static struct fb_ops carminefb_ops = { .fb_setcolreg = carmine_setcolreg, }; -static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base, +static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base, int smem_offset, struct device *device, struct fb_info **rinfo) { int ret; diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index e729fb27964..048b139f0e5 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -327,29 +327,7 @@ static const struct { #endif /* CONFIG_ZORRO */ struct cirrusfb_regs { - long freq; - long nom; - long den; - long div; - long multiplexing; - long mclk; - long divMCLK; - - long HorizRes; /* The x resolution in pixel */ - long HorizTotal; - long HorizDispEnd; - long HorizBlankStart; - long HorizBlankEnd; - long HorizSyncStart; - long HorizSyncEnd; - - long VertRes; /* the physical y resolution in scanlines */ - long VertTotal; - long VertDispEnd; - long VertSyncStart; - long VertSyncEnd; - long VertBlankStart; - long VertBlankEnd; + int multiplexing; }; #ifdef CIRRUSFB_DEBUG @@ -367,110 +345,13 @@ struct cirrusfb_info { struct cirrusfb_regs currentmode; int blank_mode; + u32 pseudo_palette[16]; - u32 pseudo_palette[16]; - -#ifdef CONFIG_ZORRO - struct zorro_dev *zdev; -#endif -#ifdef CONFIG_PCI - struct pci_dev *pdev; -#endif void (*unmap)(struct fb_info *info); }; -static unsigned cirrusfb_def_mode = 1; -static int noaccel; - -/* - * Predefined Video Modes - */ - -static const struct { - const char *name; - struct fb_var_screeninfo var; -} cirrusfb_predefined[] = { - { - /* autodetect mode */ - .name = "Autodetect", - }, { - /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */ - .name = "640x480", - .var = { - .xres = 640, - .yres = 480, - .xres_virtual = 640, - .yres_virtual = 480, - .bits_per_pixel = 8, - .red = { .length = 8 }, - .green = { .length = 8 }, - .blue = { .length = 8 }, - .width = -1, - .height = -1, - .pixclock = 40000, - .left_margin = 48, - .right_margin = 16, - .upper_margin = 32, - .lower_margin = 8, - .hsync_len = 96, - .vsync_len = 4, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - .vmode = FB_VMODE_NONINTERLACED - } - }, { - /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */ - .name = "800x600", - .var = { - .xres = 800, - .yres = 600, - .xres_virtual = 800, - .yres_virtual = 600, - .bits_per_pixel = 8, - .red = { .length = 8 }, - .green = { .length = 8 }, - .blue = { .length = 8 }, - .width = -1, - .height = -1, - .pixclock = 20000, - .left_margin = 128, - .right_margin = 16, - .upper_margin = 24, - .lower_margin = 2, - .hsync_len = 96, - .vsync_len = 6, - .vmode = FB_VMODE_NONINTERLACED - } - }, { - /* - * Modeline from XF86Config: - * Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805 - */ - /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */ - .name = "1024x768", - .var = { - .xres = 1024, - .yres = 768, - .xres_virtual = 1024, - .yres_virtual = 768, - .bits_per_pixel = 8, - .red = { .length = 8 }, - .green = { .length = 8 }, - .blue = { .length = 8 }, - .width = -1, - .height = -1, - .pixclock = 12500, - .left_margin = 144, - .right_margin = 32, - .upper_margin = 30, - .lower_margin = 2, - .hsync_len = 192, - .vsync_len = 6, - .vmode = FB_VMODE_NONINTERLACED - } - } -}; - -#define NUM_TOTAL_MODES ARRAY_SIZE(cirrusfb_predefined) +static int noaccel __devinitdata; +static char *mode_option __devinitdata = "640x480@60"; /****************************************************************************/ /**** BEGIN PROTOTYPES ******************************************************/ @@ -514,10 +395,6 @@ static struct fb_ops cirrusfb_ops = { .fb_imageblit = cirrusfb_imageblit, }; -/*--- Hardware Specific Routines -------------------------------------------*/ -static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, - struct cirrusfb_regs *regs, - struct fb_info *info); /*--- Internal routines ----------------------------------------------------*/ static void init_vgachip(struct fb_info *info); static void switch_monitor(struct cirrusfb_info *cinfo, int on); @@ -546,9 +423,7 @@ static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, u_short width, u_short height, u_char color, u_short line_length); -static void bestclock(long freq, long *best, - long *nom, long *den, - long *div, long maxfreq); +static void bestclock(long freq, int *nom, int *den, int *div); #ifdef CIRRUSFB_DEBUG static void cirrusfb_dump(void); @@ -584,45 +459,28 @@ static int cirrusfb_release(struct fb_info *info, int user) /****************************************************************************/ /**** BEGIN Hardware specific Routines **************************************/ -/* Get a good MCLK value */ -static long cirrusfb_get_mclk(long freq, int bpp, long *div) +/* Check if the MCLK is not a better clock source */ +static int cirrusfb_check_mclk(struct cirrusfb_info *cinfo, long freq) { - long mclk; + long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f; - assert(div != NULL); - - /* Calculate MCLK, in case VCLK is high enough to require > 50MHz. - * Assume a 64-bit data path for now. The formula is: - * ((B * PCLK * 2)/W) * 1.2 - * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */ - mclk = ((bpp / 8) * freq * 2) / 4; - mclk = (mclk * 12) / 10; - if (mclk < 50000) - mclk = 50000; - DPRINTK("Use MCLK of %ld kHz\n", mclk); - - /* Calculate value for SR1F. Multiply by 2 so we can round up. */ - mclk = ((mclk * 16) / 14318); - mclk = (mclk + 1) / 2; - DPRINTK("Set SR1F[5:0] to 0x%lx\n", mclk); + /* Read MCLK value */ + mclk = (14318 * mclk) >> 3; + DPRINTK("Read MCLK of %ld kHz\n", mclk); /* Determine if we should use MCLK instead of VCLK, and if so, what we - * should divide it by to get VCLK */ - switch (freq) { - case 24751 ... 25249: - *div = 2; - DPRINTK("Using VCLK = MCLK/2\n"); - break; - case 49501 ... 50499: - *div = 1; + * should divide it by to get VCLK + */ + + if (abs(freq - mclk) < 250) { DPRINTK("Using VCLK = MCLK\n"); - break; - default: - *div = 0; - break; + return 1; + } else if (abs(freq - (mclk / 2)) < 250) { + DPRINTK("Using VCLK = MCLK/2\n"); + return 2; } - return mclk; + return 0; } static int cirrusfb_check_var(struct fb_var_screeninfo *var, @@ -638,7 +496,6 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, break; /* 8 pixel per byte, only 1/4th of mem usable */ case 8: case 16: - case 24: case 32: break; /* 1 pixel == 1 byte */ default: @@ -713,7 +570,6 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, var->blue.length = 5; break; - case 24: case 32: if (isPReP) { var->red.offset = 8; @@ -767,8 +623,6 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, long maxclock; int maxclockidx = var->bits_per_pixel >> 3; struct cirrusfb_info *cinfo = info->par; - int xres, hfront, hsync, hback; - int yres, vfront, vsync, vback; switch (var->bits_per_pixel) { case 1: @@ -782,10 +636,9 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, break; case 16: - case 24: case 32: info->fix.line_length = var->xres_virtual * maxclockidx; - info->fix.visual = FB_VISUAL_DIRECTCOLOR; + info->fix.visual = FB_VISUAL_TRUECOLOR; break; default: @@ -827,90 +680,33 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, switch (var->bits_per_pixel) { case 16: case 32: - if (regs->HorizRes <= 800) + if (var->xres <= 800) /* Xbh has this type of clock for 32-bit */ freq /= 2; break; } #endif - - bestclock(freq, ®s->freq, ®s->nom, ®s->den, ®s->div, - maxclock); - regs->mclk = cirrusfb_get_mclk(freq, var->bits_per_pixel, - ®s->divMCLK); - - xres = var->xres; - hfront = var->right_margin; - hsync = var->hsync_len; - hback = var->left_margin; - - yres = var->yres; - vfront = var->lower_margin; - vsync = var->vsync_len; - vback = var->upper_margin; - - if (var->vmode & FB_VMODE_DOUBLE) { - yres *= 2; - vfront *= 2; - vsync *= 2; - vback *= 2; - } else if (var->vmode & FB_VMODE_INTERLACED) { - yres = (yres + 1) / 2; - vfront = (vfront + 1) / 2; - vsync = (vsync + 1) / 2; - vback = (vback + 1) / 2; - } - regs->HorizRes = xres; - regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5; - regs->HorizDispEnd = xres / 8 - 1; - regs->HorizBlankStart = xres / 8; - /* does not count with "-5" */ - regs->HorizBlankEnd = regs->HorizTotal + 5; - regs->HorizSyncStart = (xres + hfront) / 8 + 1; - regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1; - - regs->VertRes = yres; - regs->VertTotal = yres + vfront + vsync + vback - 2; - regs->VertDispEnd = yres - 1; - regs->VertBlankStart = yres; - regs->VertBlankEnd = regs->VertTotal; - regs->VertSyncStart = yres + vfront - 1; - regs->VertSyncEnd = yres + vfront + vsync - 1; - - if (regs->VertRes >= 1024) { - regs->VertTotal /= 2; - regs->VertSyncStart /= 2; - regs->VertSyncEnd /= 2; - regs->VertDispEnd /= 2; - } - if (regs->multiplexing) { - regs->HorizTotal /= 2; - regs->HorizSyncStart /= 2; - regs->HorizSyncEnd /= 2; - regs->HorizDispEnd /= 2; - } - return 0; } -static void cirrusfb_set_mclk(const struct cirrusfb_info *cinfo, int val, - int div) +static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo, + int div) { + unsigned char old1f, old1e; assert(cinfo != NULL); + old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40; - if (div == 2) { - /* VCLK = MCLK/2 */ - unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E); - vga_wseq(cinfo->regbase, CL_SEQR1E, old | 0x1); - vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); - } else if (div == 1) { - /* VCLK = MCLK */ - unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E); - vga_wseq(cinfo->regbase, CL_SEQR1E, old & ~0x1); - vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f)); - } else { - vga_wseq(cinfo->regbase, CL_SEQR1F, val & 0x3f); + if (div) { + DPRINTK("Set %s as pixclock source.\n", + (div == 2) ? "MCLK/2" : "MCLK"); + old1f |= 0x40; + old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1; + if (div == 2) + old1e |= 1; + + vga_wseq(cinfo->regbase, CL_SEQR1E, old1e); } + vga_wseq(cinfo->regbase, CL_SEQR1F, old1f); } /************************************************************************* @@ -927,6 +723,10 @@ static int cirrusfb_set_par_foo(struct fb_info *info) unsigned char tmp; int offset = 0, err; const struct cirrusfb_board_info_rec *bi; + int hdispend, hsyncstart, hsyncend, htotal; + int yres, vdispend, vsyncstart, vsyncend, vtotal; + long freq; + int nom, den, div; DPRINTK("ENTER\n"); DPRINTK("Requested mode: %dx%dx%d\n", @@ -944,76 +744,117 @@ static int cirrusfb_set_par_foo(struct fb_info *info) bi = &cirrusfb_board_info[cinfo->btype]; + hsyncstart = var->xres + var->right_margin; + hsyncend = hsyncstart + var->hsync_len; + htotal = (hsyncend + var->left_margin) / 8 - 5; + hdispend = var->xres / 8 - 1; + hsyncstart = hsyncstart / 8 + 1; + hsyncend = hsyncend / 8 + 1; + + yres = var->yres; + vsyncstart = yres + var->lower_margin; + vsyncend = vsyncstart + var->vsync_len; + vtotal = vsyncend + var->upper_margin; + vdispend = yres - 1; + + if (var->vmode & FB_VMODE_DOUBLE) { + yres *= 2; + vsyncstart *= 2; + vsyncend *= 2; + vtotal *= 2; + } else if (var->vmode & FB_VMODE_INTERLACED) { + yres = (yres + 1) / 2; + vsyncstart = (vsyncstart + 1) / 2; + vsyncend = (vsyncend + 1) / 2; + vtotal = (vtotal + 1) / 2; + } + + vtotal -= 2; + vsyncstart -= 1; + vsyncend -= 1; + + if (yres >= 1024) { + vtotal /= 2; + vsyncstart /= 2; + vsyncend /= 2; + vdispend /= 2; + } + if (regs.multiplexing) { + htotal /= 2; + hsyncstart /= 2; + hsyncend /= 2; + hdispend /= 2; + } /* unlock register VGA_CRTC_H_TOTAL..CRT7 */ vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ /* if debugging is enabled, all parameters get output before writing */ - DPRINTK("CRT0: %ld\n", regs.HorizTotal); - vga_wcrt(regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal); + DPRINTK("CRT0: %d\n", htotal); + vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal); - DPRINTK("CRT1: %ld\n", regs.HorizDispEnd); - vga_wcrt(regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd); + DPRINTK("CRT1: %d\n", hdispend); + vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend); - DPRINTK("CRT2: %ld\n", regs.HorizBlankStart); - vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart); + DPRINTK("CRT2: %d\n", var->xres / 8); + vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8); /* + 128: Compatible read */ - DPRINTK("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); + DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32); vga_wcrt(regbase, VGA_CRTC_H_BLANK_END, - 128 + (regs.HorizBlankEnd % 32)); + 128 + ((htotal + 5) % 32)); - DPRINTK("CRT4: %ld\n", regs.HorizSyncStart); - vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart); + DPRINTK("CRT4: %d\n", hsyncstart); + vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart); - tmp = regs.HorizSyncEnd % 32; - if (regs.HorizBlankEnd & 32) + tmp = hsyncend % 32; + if ((htotal + 5) & 32) tmp += 128; DPRINTK("CRT5: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp); - DPRINTK("CRT6: %ld\n", regs.VertTotal & 0xff); - vga_wcrt(regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff)); + DPRINTK("CRT6: %d\n", vtotal & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff); tmp = 16; /* LineCompare bit #9 */ - if (regs.VertTotal & 256) + if (vtotal & 256) tmp |= 1; - if (regs.VertDispEnd & 256) + if (vdispend & 256) tmp |= 2; - if (regs.VertSyncStart & 256) + if (vsyncstart & 256) tmp |= 4; - if (regs.VertBlankStart & 256) + if ((vdispend + 1) & 256) tmp |= 8; - if (regs.VertTotal & 512) + if (vtotal & 512) tmp |= 32; - if (regs.VertDispEnd & 512) + if (vdispend & 512) tmp |= 64; - if (regs.VertSyncStart & 512) + if (vsyncstart & 512) tmp |= 128; DPRINTK("CRT7: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp); tmp = 0x40; /* LineCompare bit #8 */ - if (regs.VertBlankStart & 512) + if ((vdispend + 1) & 512) tmp |= 0x20; if (var->vmode & FB_VMODE_DOUBLE) tmp |= 0x80; DPRINTK("CRT9: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp); - DPRINTK("CRT10: %ld\n", regs.VertSyncStart & 0xff); - vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, regs.VertSyncStart & 0xff); + DPRINTK("CRT10: %d\n", vsyncstart & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff); - DPRINTK("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16); - vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, regs.VertSyncEnd % 16 + 64 + 32); + DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16); + vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32); - DPRINTK("CRT12: %ld\n", regs.VertDispEnd & 0xff); - vga_wcrt(regbase, VGA_CRTC_V_DISP_END, regs.VertDispEnd & 0xff); + DPRINTK("CRT12: %d\n", vdispend & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff); - DPRINTK("CRT15: %ld\n", regs.VertBlankStart & 0xff); - vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, regs.VertBlankStart & 0xff); + DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff); - DPRINTK("CRT16: %ld\n", regs.VertBlankEnd & 0xff); - vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, regs.VertBlankEnd & 0xff); + DPRINTK("CRT16: %d\n", vtotal & 0xff); + vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff); DPRINTK("CRT18: 0xff\n"); vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff); @@ -1021,38 +862,53 @@ static int cirrusfb_set_par_foo(struct fb_info *info) tmp = 0; if (var->vmode & FB_VMODE_INTERLACED) tmp |= 1; - if (regs.HorizBlankEnd & 64) + if ((htotal + 5) & 64) tmp |= 16; - if (regs.HorizBlankEnd & 128) + if ((htotal + 5) & 128) tmp |= 32; - if (regs.VertBlankEnd & 256) + if (vtotal & 256) tmp |= 64; - if (regs.VertBlankEnd & 512) + if (vtotal & 512) tmp |= 128; DPRINTK("CRT1a: %d\n", tmp); vga_wcrt(regbase, CL_CRT1A, tmp); + freq = PICOS2KHZ(var->pixclock); + bestclock(freq, &nom, &den, &div); + /* set VCLK0 */ /* hardware RefClock: 14.31818 MHz */ /* formula: VClk = (OSC * N) / (D * (1+P)) */ /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ - vga_wseq(regbase, CL_SEQRB, regs.nom); - tmp = regs.den << 1; - if (regs.div != 0) - tmp |= 1; + if (cinfo->btype == BT_ALPINE) { + /* if freq is close to mclk or mclk/2 select mclk + * as clock source + */ + int divMCLK = cirrusfb_check_mclk(cinfo, freq); + if (divMCLK) { + nom = 0; + cirrusfb_set_mclk_as_source(cinfo, divMCLK); + } + } + if (nom) { + vga_wseq(regbase, CL_SEQRB, nom); + tmp = den << 1; + if (div != 0) + tmp |= 1; - /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ - if ((cinfo->btype == BT_SD64) || - (cinfo->btype == BT_ALPINE) || - (cinfo->btype == BT_GD5480)) - tmp |= 0x80; + /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ + if ((cinfo->btype == BT_SD64) || + (cinfo->btype == BT_ALPINE) || + (cinfo->btype == BT_GD5480)) + tmp |= 0x80; - DPRINTK("CL_SEQR1B: %ld\n", (long) tmp); - vga_wseq(regbase, CL_SEQR1B, tmp); + DPRINTK("CL_SEQR1B: %ld\n", (long) tmp); + vga_wseq(regbase, CL_SEQR1B, tmp); + } - if (regs.VertRes >= 1024) + if (yres >= 1024) /* 1280x1024 */ vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7); else @@ -1066,7 +922,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) /* don't know if it would hurt to also program this if no interlaced */ /* mode is used, but I feel better this way.. :-) */ if (var->vmode & FB_VMODE_INTERLACED) - vga_wcrt(regbase, VGA_CRTC_REGS, regs.HorizTotal / 2); + vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2); else vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ @@ -1240,7 +1096,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) case BT_ALPINE: DPRINTK(" (for GD543x)\n"); - cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); /* We already set SRF and SR1F */ break; @@ -1312,11 +1167,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) case BT_ALPINE: DPRINTK(" (for GD543x)\n"); - if (regs.HorizRes >= 1024) - vga_wseq(regbase, CL_SEQR7, 0xa7); - else - vga_wseq(regbase, CL_SEQR7, 0xa3); - cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); + vga_wseq(regbase, CL_SEQR7, 0xa7); break; case BT_GD5480: @@ -1360,7 +1211,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ else if (var->bits_per_pixel == 32) { - DPRINTK("cirrusfb: preparing for 24/32 bit deep display\n"); + DPRINTK("cirrusfb: preparing for 32 bit deep display\n"); switch (cinfo->btype) { case BT_SD64: /* Extended Sequencer Mode: 256c col. mode */ @@ -1394,7 +1245,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) case BT_ALPINE: DPRINTK(" (for GD543x)\n"); vga_wseq(regbase, CL_SEQR7, 0xa9); - cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK); break; case BT_GD5480: @@ -1949,8 +1799,6 @@ static void init_vgachip(struct fb_info *info) /* misc... */ WHDR(cinfo, 0); /* Hidden DAC register: - */ - printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", - info->screen_size); DPRINTK("EXIT\n"); return; } @@ -2122,7 +1970,7 @@ static int release_io_ports; * based on the DRAM bandwidth bit and DRAM bank switching bit. This * works with 1MB, 2MB and 4MB configurations (which the Motorola boards * seem to have. */ -static unsigned int cirrusfb_get_memsize(u8 __iomem *regbase) +static unsigned int __devinit cirrusfb_get_memsize(u8 __iomem *regbase) { unsigned long mem; unsigned char SRF; @@ -2188,8 +2036,7 @@ static void get_pci_addrs(const struct pci_dev *pdev, static void cirrusfb_pci_unmap(struct fb_info *info) { - struct cirrusfb_info *cinfo = info->par; - struct pci_dev *pdev = cinfo->pdev; + struct pci_dev *pdev = to_pci_dev(info->device); iounmap(info->screen_base); #if 0 /* if system didn't claim this region, we would... */ @@ -2205,20 +2052,22 @@ static void cirrusfb_pci_unmap(struct fb_info *info) static void __devexit cirrusfb_zorro_unmap(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; - zorro_release_device(cinfo->zdev); + struct zorro_dev *zdev = to_zorro_dev(info->device); + + zorro_release_device(zdev); if (cinfo->btype == BT_PICASSO4) { cinfo->regbase -= 0x600000; iounmap((void *)cinfo->regbase); iounmap(info->screen_base); } else { - if (zorro_resource_start(cinfo->zdev) > 0x01000000) + if (zorro_resource_start(zdev) > 0x01000000) iounmap(info->screen_base); } } #endif /* CONFIG_ZORRO */ -static int cirrusfb_set_fbinfo(struct fb_info *info) +static int __devinit cirrusfb_set_fbinfo(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; struct fb_var_screeninfo *var = &info->var; @@ -2235,7 +2084,7 @@ static int cirrusfb_set_fbinfo(struct fb_info *info) if (cinfo->btype == BT_GD5480) { if (var->bits_per_pixel == 16) info->screen_base += 1 * MB_; - if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32) + if (var->bits_per_pixel == 32) info->screen_base += 2 * MB_; } @@ -2262,7 +2111,7 @@ static int cirrusfb_set_fbinfo(struct fb_info *info) return 0; } -static int cirrusfb_register(struct fb_info *info) +static int __devinit cirrusfb_register(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; int err; @@ -2278,23 +2127,27 @@ static int cirrusfb_register(struct fb_info *info) /* sanity checks */ assert(btype != BT_NONE); + /* set all the vital stuff */ + cirrusfb_set_fbinfo(info); + DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base); - /* Make pretend we've set the var so our structures are in a "good" */ - /* state, even though we haven't written the mode to the hw yet... */ - info->var = cirrusfb_predefined[cirrusfb_def_mode].var; + err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); + if (!err) { + DPRINTK("wrong initial video mode\n"); + err = -EINVAL; + goto err_dealloc_cmap; + } + info->var.activate = FB_ACTIVATE_NOW; err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info); if (err < 0) { /* should never happen */ DPRINTK("choking on default var... umm, no good.\n"); - goto err_unmap_cirrusfb; + goto err_dealloc_cmap; } - /* set all the vital stuff */ - cirrusfb_set_fbinfo(info); - err = register_framebuffer(info); if (err < 0) { printk(KERN_ERR "cirrusfb: could not register " @@ -2307,7 +2160,6 @@ static int cirrusfb_register(struct fb_info *info) err_dealloc_cmap: fb_dealloc_cmap(&info->cmap); -err_unmap_cirrusfb: cinfo->unmap(info); framebuffer_release(info); return err; @@ -2330,8 +2182,8 @@ static void __devexit cirrusfb_cleanup(struct fb_info *info) } #ifdef CONFIG_PCI -static int cirrusfb_pci_register(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, + const struct pci_device_id *ent) { struct cirrusfb_info *cinfo; struct fb_info *info; @@ -2353,7 +2205,6 @@ static int cirrusfb_pci_register(struct pci_dev *pdev, } cinfo = info->par; - cinfo->pdev = pdev; cinfo->btype = btype = (enum cirrus_board) ent->driver_data; DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n", @@ -2459,8 +2310,8 @@ static struct pci_driver cirrusfb_pci_driver = { #endif /* CONFIG_PCI */ #ifdef CONFIG_ZORRO -static int cirrusfb_zorro_register(struct zorro_dev *z, - const struct zorro_device_id *ent) +static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, + const struct zorro_device_id *ent) { struct cirrusfb_info *cinfo; struct fb_info *info; @@ -2489,7 +2340,6 @@ static int cirrusfb_zorro_register(struct zorro_dev *z, assert(z); assert(btype != BT_NONE); - cinfo->zdev = z; board_addr = zorro_resource_start(z); board_size = zorro_resource_len(z); info->screen_size = size; @@ -2621,17 +2471,17 @@ static int __init cirrusfb_setup(char *options) { return 0; while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) continue; + if (!*this_opt) + continue; DPRINTK("cirrusfb_setup: option '%s'\n", this_opt); - for (i = 0; i < NUM_TOTAL_MODES; i++) { - sprintf(s, "mode:%s", cirrusfb_predefined[i].name); - if (strcmp(this_opt, s) == 0) - cirrusfb_def_mode = i; - } if (!strcmp(this_opt, "noaccel")) noaccel = 1; + else if (!strncmp(this_opt, "mode:", 5)) + mode_option = this_opt + 5; + else + mode_option = this_opt; } return 0; } @@ -2657,6 +2507,11 @@ static void __exit cirrusfb_exit(void) module_init(cirrusfb_init); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'"); +module_param(noaccel, bool, 0); +MODULE_PARM_DESC(noaccel, "Disable acceleration"); + #ifdef MODULE module_exit(cirrusfb_exit); #endif @@ -3050,16 +2905,14 @@ static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, * bestclock() - determine closest possible clock lower(?) than the * desired pixel clock **************************************************************************/ -static void bestclock(long freq, long *best, long *nom, - long *den, long *div, long maxfreq) +static void bestclock(long freq, int *nom, int *den, int *div) { - long n, h, d, f; + int n, d; + long h, diff; - assert(best != NULL); assert(nom != NULL); assert(den != NULL); assert(div != NULL); - assert(maxfreq > 0); *nom = 0; *den = 0; @@ -3070,51 +2923,47 @@ static void bestclock(long freq, long *best, long *nom, if (freq < 8000) freq = 8000; - if (freq > maxfreq) - freq = maxfreq; - - *best = 0; - f = freq * 10; + diff = freq; for (n = 32; n < 128; n++) { - d = (143181 * n) / f; + int s = 0; + + d = (14318 * n) / freq; if ((d >= 7) && (d <= 63)) { - if (d > 31) - d = (d / 2) * 2; - h = (14318 * n) / d; - if (abs(h - freq) < abs(*best - freq)) { - *best = h; + int temp = d; + + if (temp > 31) { + s = 1; + temp >>= 1; + } + h = ((14318 * n) / temp) >> s; + h = h > freq ? h - freq : freq - h; + if (h < diff) { + diff = h; *nom = n; - if (d < 32) { - *den = d; - *div = 0; - } else { - *den = d / 2; - *div = 1; - } + *den = temp; + *div = s; } } - d = DIV_ROUND_UP(143181 * n, f); + d++; if ((d >= 7) && (d <= 63)) { - if (d > 31) - d = (d / 2) * 2; - h = (14318 * n) / d; - if (abs(h - freq) < abs(*best - freq)) { - *best = h; + if (d > 31) { + s = 1; + d >>= 1; + } + h = ((14318 * n) / d) >> s; + h = h > freq ? h - freq : freq - h; + if (h < diff) { + diff = h; *nom = n; - if (d < 32) { - *den = d; - *div = 0; - } else { - *den = d / 2; - *div = 1; - } + *den = d; + *div = s; } } } DPRINTK("Best possible values for given frequency:\n"); - DPRINTK(" best: %ld kHz nom: %ld den: %ld div: %ld\n", + DPRINTK(" freq: %ld kHz nom: %d den: %d div: %d\n", freq, *nom, *den, *div); DPRINTK("EXIT\n"); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 9cbff84b787..93a080e827c 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -1855,8 +1855,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; - unsigned short saved_ec; - int ret; if (fbcon_is_inactive(vc, info)) return -EINVAL; @@ -1869,11 +1867,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, * whole screen (prevents flicker). */ - saved_ec = vc->vc_video_erase_char; - vc->vc_video_erase_char = vc->vc_scrl_erase_char; - - ret = 0; - switch (dir) { case SM_UP: if (count > vc->vc_rows) /* Maximum realistic size */ @@ -1890,9 +1883,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_scrl_erase_char, + vc->vc_video_erase_char, vc->vc_size_row * count); - ret = 1; + return 1; break; case SCROLL_WRAP_MOVE: @@ -1962,10 +1955,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_scrl_erase_char, + vc->vc_video_erase_char, vc->vc_size_row * count); - ret = 1; - break; + return 1; } break; @@ -1982,9 +1974,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_scrl_erase_char, + vc->vc_video_erase_char, vc->vc_size_row * count); - ret = 1; + return 1; break; case SCROLL_WRAP_MOVE: @@ -2052,15 +2044,12 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_scrl_erase_char, + vc->vc_video_erase_char, vc->vc_size_row * count); - ret = 1; - break; + return 1; } - break; } - vc->vc_video_erase_char = saved_ec; - return ret; + return 0; } @@ -2522,9 +2511,6 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, c = vc->vc_video_erase_char; vc->vc_video_erase_char = ((c & 0xfe00) >> 1) | (c & 0xff); - c = vc->vc_scrl_erase_char; - vc->vc_scrl_erase_char = - ((c & 0xFE00) >> 1) | (c & 0xFF); vc->vc_attr >>= 1; } } else if (!vc->vc_hi_font_mask && cnt == 512) { @@ -2555,14 +2541,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, if (vc->vc_can_do_color) { vc->vc_video_erase_char = ((c & 0xff00) << 1) | (c & 0xff); - c = vc->vc_scrl_erase_char; - vc->vc_scrl_erase_char = - ((c & 0xFF00) << 1) | (c & 0xFF); vc->vc_attr <<= 1; - } else { + } else vc->vc_video_erase_char = c & ~0x100; - vc->vc_scrl_erase_char = c & ~0x100; - } } } @@ -2996,8 +2977,8 @@ static void fbcon_set_all_vcs(struct fb_info *info) p = &fb_display[vc->vc_num]; set_blitting_type(vc, info); var_to_display(p, &info->var, info); - cols = FBCON_SWAP(p->rotate, info->var.xres, info->var.yres); - rows = FBCON_SWAP(p->rotate, info->var.yres, info->var.xres); + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); cols /= vc->vc_font.width; rows /= vc->vc_font.height; vc_resize(vc, cols, rows); diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 9901064199b..dd3eaaad444 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -533,7 +533,7 @@ static void mdacon_cursor(struct vc_data *c, int mode) static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) { - u16 eattr = mda_convert_attr(c->vc_scrl_erase_char); + u16 eattr = mda_convert_attr(c->vc_video_erase_char); if (!lines) return 0; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 4055dbdd1b4..491c1c1baf4 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -170,12 +170,12 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) switch (dir) { case SM_UP: sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols); - sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); + sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char); break; case SM_DOWN: sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols); - sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); + sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char); break; } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index bd1f57b259d..448d209a0bf 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -239,8 +239,7 @@ static void vgacon_restore_screen(struct vc_data *c) static int vgacon_scrolldelta(struct vc_data *c, int lines) { - int start, end, count, soff, diff; - void *d, *s; + int start, end, count, soff; if (!lines) { c->vc_visible_origin = c->vc_origin; @@ -287,29 +286,29 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines) if (count > c->vc_rows) count = c->vc_rows; - diff = c->vc_rows - count; + if (count) { + int copysize; - d = (void *) c->vc_origin; - s = (void *) c->vc_screenbuf; + int diff = c->vc_rows - count; + void *d = (void *) c->vc_origin; + void *s = (void *) c->vc_screenbuf; - while (count--) { - scr_memcpyw(d, vgacon_scrollback + soff, c->vc_size_row); - d += c->vc_size_row; - soff += c->vc_size_row; + count *= c->vc_size_row; + /* how much memory to end of buffer left? */ + copysize = min(count, vgacon_scrollback_size - soff); + scr_memcpyw(d, vgacon_scrollback + soff, copysize); + d += copysize; + count -= copysize; - if (soff >= vgacon_scrollback_size) - soff = 0; - } + if (count) { + scr_memcpyw(d, vgacon_scrollback, count); + d += count; + } - if (diff == c->vc_rows) { + if (diff) + scr_memcpyw(d, s, diff * c->vc_size_row); + } else vgacon_cursor(c, CM_MOVE); - } else { - while (diff--) { - scr_memcpyw(d, s, c->vc_size_row); - d += c->vc_size_row; - s += c->vc_size_row; - } - } return 1; } @@ -1350,7 +1349,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, } else c->vc_origin += delta; scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - - delta), c->vc_scrl_erase_char, + delta), c->vc_video_erase_char, delta); } else { if (oldo - delta < vga_vram_base) { @@ -1363,7 +1362,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, } else c->vc_origin -= delta; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; - scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char, + scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, delta); } c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index bd779ae44b1..daf9b81878a 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -12,6 +12,7 @@ #include <linux/fb.h> #include <linux/platform_device.h> #include <linux/screen_info.h> +#include <linux/dmi.h> #include <video/vga.h> @@ -33,6 +34,105 @@ static struct fb_fix_screeninfo efifb_fix __initdata = { .visual = FB_VISUAL_TRUECOLOR, }; +enum { + M_I17, /* 17-Inch iMac */ + M_I20, /* 20-Inch iMac */ + M_I20_SR, /* 20-Inch iMac (Santa Rosa) */ + M_I24, /* 24-Inch iMac */ + M_MINI, /* Mac Mini */ + M_MB, /* MacBook */ + M_MB_2, /* MacBook, 2nd rev. */ + M_MB_3, /* MacBook, 3rd rev. */ + M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */ + M_MBA, /* MacBook Air */ + M_MBP, /* MacBook Pro */ + M_MBP_2, /* MacBook Pro 2nd gen */ + M_MBP_SR, /* MacBook Pro (Santa Rosa) */ + M_MBP_4, /* MacBook Pro, 4th gen */ + M_UNKNOWN /* placeholder */ +}; + +static struct efifb_dmi_info { + char *optname; + unsigned long base; + int stride; + int width; + int height; +} dmi_list[] = { + [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900 }, + [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */ + [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 }, + [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */ + [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 }, + [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 }, + [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 }, + [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 }, + [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */ + [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 }, + [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 }, + [M_UNKNOWN] = { NULL, 0, 0, 0, 0 } +}; + +static int set_system(const struct dmi_system_id *id); + +#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \ + { set_system, name, { \ + DMI_MATCH(DMI_BIOS_VENDOR, vendor), \ + DMI_MATCH(DMI_PRODUCT_NAME, name) }, \ + &dmi_list[enumid] } + +static struct dmi_system_id __initdata dmi_system_table[] = { + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17), + /* At least one of these two will be right; maybe both? */ + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20), + /* At least one of these two will be right; maybe both? */ + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB), + /* At least one of these two will be right; maybe both? */ + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB), + /* At least one of these two will be right; maybe both? */ + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2), + EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4), + {}, +}; + +static int set_system(const struct dmi_system_id *id) +{ + struct efifb_dmi_info *info = id->driver_data; + if (info->base == 0) + return -ENODEV; + + printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " + "(%dx%d, stride %d)\n", id->ident, + (void *)info->base, info->width, info->height, + info->stride); + + /* Trust the bootloader over the DMI tables */ + if (screen_info.lfb_base == 0) + screen_info.lfb_base = info->base; + if (screen_info.lfb_linelength == 0) + screen_info.lfb_linelength = info->stride; + if (screen_info.lfb_width == 0) + screen_info.lfb_width = info->width; + if (screen_info.lfb_height == 0) + screen_info.lfb_height = info->height; + + return 0; +} + static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) @@ -67,6 +167,38 @@ static struct fb_ops efifb_ops = { .fb_imageblit = cfb_imageblit, }; +static int __init efifb_setup(char *options) +{ + char *this_opt; + int i; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) continue; + + for (i = 0; i < M_UNKNOWN; i++) { + if (!strcmp(this_opt, dmi_list[i].optname) && + dmi_list[i].base != 0) { + screen_info.lfb_base = dmi_list[i].base; + screen_info.lfb_linelength = dmi_list[i].stride; + screen_info.lfb_width = dmi_list[i].width; + screen_info.lfb_height = dmi_list[i].height; + } + } + if (!strncmp(this_opt, "base:", 5)) + screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "stride:", 7)) + screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4; + else if (!strncmp(this_opt, "height:", 7)) + screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "width:", 6)) + screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); + } + return 0; +} + static int __init efifb_probe(struct platform_device *dev) { struct fb_info *info; @@ -74,6 +206,26 @@ static int __init efifb_probe(struct platform_device *dev) unsigned int size_vmode; unsigned int size_remap; unsigned int size_total; + int request_succeeded = 0; + + printk(KERN_INFO "efifb: probing for efifb\n"); + + if (!screen_info.lfb_depth) + screen_info.lfb_depth = 32; + if (!screen_info.pages) + screen_info.pages = 1; + + /* just assume they're all unset if any are */ + if (!screen_info.blue_size) { + screen_info.blue_size = 8; + screen_info.blue_pos = 0; + screen_info.green_size = 8; + screen_info.green_pos = 8; + screen_info.red_size = 8; + screen_info.red_pos = 16; + screen_info.rsvd_size = 8; + screen_info.rsvd_pos = 24; + } efifb_fix.smem_start = screen_info.lfb_base; efifb_defined.bits_per_pixel = screen_info.lfb_depth; @@ -98,21 +250,25 @@ static int __init efifb_probe(struct platform_device *dev) * option to simply use size_total as that * wastes plenty of kernel address space. */ size_remap = size_vmode * 2; - if (size_remap < size_vmode) - size_remap = size_vmode; if (size_remap > size_total) size_remap = size_total; + if (size_remap % PAGE_SIZE) + size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE); efifb_fix.smem_len = size_remap; - if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb")) + if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) { + request_succeeded = 1; + } else { /* We cannot make this fatal. Sometimes this comes from magic spaces our resource handlers simply don't know about */ printk(KERN_WARNING "efifb: cannot reserve video memory at 0x%lx\n", efifb_fix.smem_start); + } info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); if (!info) { + printk(KERN_ERR "efifb: cannot allocate framebuffer\n"); err = -ENOMEM; goto err_release_mem; } @@ -125,7 +281,7 @@ static int __init efifb_probe(struct platform_device *dev) "0x%x @ 0x%lx\n", efifb_fix.smem_len, efifb_fix.smem_start); err = -EIO; - goto err_unmap; + goto err_release_fb; } printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, " @@ -178,25 +334,27 @@ static int __init efifb_probe(struct platform_device *dev) info->fix = efifb_fix; info->flags = FBINFO_FLAG_DEFAULT; - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { - err = -ENOMEM; + if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) { + printk(KERN_ERR "efifb: cannot allocate colormap\n"); goto err_unmap; } - if (register_framebuffer(info) < 0) { - err = -EINVAL; + if ((err = register_framebuffer(info)) < 0) { + printk(KERN_ERR "efifb: cannot register framebuffer\n"); goto err_fb_dealoc; } printk(KERN_INFO "fb%d: %s frame buffer device\n", - info->node, info->fix.id); + info->node, info->fix.id); return 0; err_fb_dealoc: fb_dealloc_cmap(&info->cmap); err_unmap: iounmap(info->screen_base); +err_release_fb: framebuffer_release(info); err_release_mem: - release_mem_region(efifb_fix.smem_start, size_total); + if (request_succeeded) + release_mem_region(efifb_fix.smem_start, size_total); return err; } @@ -214,9 +372,22 @@ static struct platform_device efifb_device = { static int __init efifb_init(void) { int ret; + char *option = NULL; if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) return -ENODEV; + dmi_check_system(dmi_system_table); + + if (fb_get_options("efifb", &option)) + return -ENODEV; + efifb_setup(option); + + /* We don't get linelength from UGA Draw Protocol, only from + * EFI Graphics Protocol. So if it's not in DMI, and it's not + * passed in from the user, we really can't use the framebuffer. + */ + if (!screen_info.lfb_linelength) + return -ENODEV; ret = platform_driver_register(&efifb_driver); diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 6a0aa180c26..5c1a2c01778 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -564,7 +564,13 @@ static void get_detailed_timing(unsigned char *block, mode->sync |= FB_SYNC_VERT_HIGH_ACT; mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) * (V_ACTIVE + V_BLANKING)); - mode->vmode = 0; + if (INTERLACED) { + mode->yres *= 2; + mode->upper_margin *= 2; + mode->lower_margin *= 2; + mode->vsync_len *= 2; + mode->vmode |= FB_VMODE_INTERLACED; + } mode->flag = FB_MODE_IS_DETAILED; DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000); diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c index 9366ef2bb5f..e69de29bb2d 100644 --- a/drivers/video/imacfb.c +++ b/drivers/video/imacfb.c @@ -1,376 +0,0 @@ -/* - * framebuffer driver for Intel Based Mac's - * - * (c) 2006 Edgar Hucek <gimli@dark-green.com> - * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de> - * - */ - -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fb.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/screen_info.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/dmi.h> -#include <linux/efi.h> - -#include <asm/io.h> - -#include <video/vga.h> - -typedef enum _MAC_TYPE { - M_I17, - M_I20, - M_MINI, - M_MACBOOK, - M_UNKNOWN -} MAC_TYPE; - -/* --------------------------------------------------------------------- */ - -static struct fb_var_screeninfo imacfb_defined __initdata = { - .activate = FB_ACTIVATE_NOW, - .height = -1, - .width = -1, - .right_margin = 32, - .upper_margin = 16, - .lower_margin = 4, - .vsync_len = 4, - .vmode = FB_VMODE_NONINTERLACED, -}; - -static struct fb_fix_screeninfo imacfb_fix __initdata = { - .id = "IMAC VGA", - .type = FB_TYPE_PACKED_PIXELS, - .accel = FB_ACCEL_NONE, - .visual = FB_VISUAL_TRUECOLOR, -}; - -static int inverse; -static int model = M_UNKNOWN; -static int manual_height; -static int manual_width; - -static int set_system(const struct dmi_system_id *id) -{ - printk(KERN_INFO "imacfb: %s detected - set system to %ld\n", - id->ident, (long)id->driver_data); - - model = (long)id->driver_data; - - return 0; -} - -static struct dmi_system_id __initdata dmi_system_table[] = { - { set_system, "iMac4,1", { - DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME,"iMac4,1") }, (void*)M_I17}, - { set_system, "MacBookPro1,1", { - DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro1,1") }, (void*)M_I17}, - { set_system, "MacBook1,1", { - DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME,"MacBook1,1")}, (void *)M_MACBOOK}, - { set_system, "Macmini1,1", { - DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME,"Macmini1,1")}, (void *)M_MINI}, - {}, -}; - -#define DEFAULT_FB_MEM 1024*1024*16 - -/* --------------------------------------------------------------------- */ - -static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - /* - * Set a single color register. The values supplied are - * already rounded down to the hardware's capabilities - * (according to the entries in the `var' structure). Return - * != 0 for invalid regno. - */ - - if (regno >= info->cmap.len) - return 1; - - if (regno < 16) { - red >>= 8; - green >>= 8; - blue >>= 8; - ((u32 *)(info->pseudo_palette))[regno] = - (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset); - } - return 0; -} - -static struct fb_ops imacfb_ops = { - .owner = THIS_MODULE, - .fb_setcolreg = imacfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - -static int __init imacfb_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) continue; - - if (!strcmp(this_opt, "inverse")) - inverse = 1; - else if (!strcmp(this_opt, "i17")) - model = M_I17; - else if (!strcmp(this_opt, "i20")) - model = M_I20; - else if (!strcmp(this_opt, "mini")) - model = M_MINI; - else if (!strcmp(this_opt, "macbook")) - model = M_MACBOOK; - else if (!strncmp(this_opt, "height:", 7)) - manual_height = simple_strtoul(this_opt+7, NULL, 0); - else if (!strncmp(this_opt, "width:", 6)) - manual_width = simple_strtoul(this_opt+6, NULL, 0); - } - return 0; -} - -static int __init imacfb_probe(struct platform_device *dev) -{ - struct fb_info *info; - int err; - unsigned int size_vmode; - unsigned int size_remap; - unsigned int size_total; - - screen_info.lfb_depth = 32; - screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000; - screen_info.pages=1; - screen_info.blue_size = 8; - screen_info.blue_pos = 0; - screen_info.green_size = 8; - screen_info.green_pos = 8; - screen_info.red_size = 8; - screen_info.red_pos = 16; - screen_info.rsvd_size = 8; - screen_info.rsvd_pos = 24; - - switch (model) { - case M_I17: - screen_info.lfb_width = 1440; - screen_info.lfb_height = 900; - screen_info.lfb_linelength = 1472 * 4; - screen_info.lfb_base = 0x80010000; - break; - case M_I20: - screen_info.lfb_width = 1680; - screen_info.lfb_height = 1050; - screen_info.lfb_linelength = 1728 * 4; - screen_info.lfb_base = 0x80010000; - break; - case M_MINI: - screen_info.lfb_width = 1024; - screen_info.lfb_height = 768; - screen_info.lfb_linelength = 2048 * 4; - screen_info.lfb_base = 0x80000000; - break; - case M_MACBOOK: - screen_info.lfb_width = 1280; - screen_info.lfb_height = 800; - screen_info.lfb_linelength = 2048 * 4; - screen_info.lfb_base = 0x80000000; - break; - } - - /* if the user wants to manually specify height/width, - we will override the defaults */ - /* TODO: eventually get auto-detection working */ - if (manual_height > 0) - screen_info.lfb_height = manual_height; - if (manual_width > 0) - screen_info.lfb_width = manual_width; - - imacfb_fix.smem_start = screen_info.lfb_base; - imacfb_defined.bits_per_pixel = screen_info.lfb_depth; - imacfb_defined.xres = screen_info.lfb_width; - imacfb_defined.yres = screen_info.lfb_height; - imacfb_fix.line_length = screen_info.lfb_linelength; - - /* size_vmode -- that is the amount of memory needed for the - * used video mode, i.e. the minimum amount of - * memory we need. */ - size_vmode = imacfb_defined.yres * imacfb_fix.line_length; - - /* size_total -- all video memory we have. Used for - * entries, ressource allocation and bounds - * checking. */ - size_total = screen_info.lfb_size * 65536; - if (size_total < size_vmode) - size_total = size_vmode; - - /* size_remap -- the amount of video memory we are going to - * use for imacfb. With modern cards it is no - * option to simply use size_total as that - * wastes plenty of kernel address space. */ - size_remap = size_vmode * 2; - if (size_remap < size_vmode) - size_remap = size_vmode; - if (size_remap > size_total) - size_remap = size_total; - imacfb_fix.smem_len = size_remap; - - if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) { - printk(KERN_WARNING - "imacfb: cannot reserve video memory at 0x%lx\n", - imacfb_fix.smem_start); - /* We cannot make this fatal. Sometimes this comes from magic - spaces our resource handlers simply don't know about */ - } - - info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); - if (!info) { - err = -ENOMEM; - goto err_release_mem; - } - info->pseudo_palette = info->par; - info->par = NULL; - - info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len); - if (!info->screen_base) { - printk(KERN_ERR "imacfb: abort, cannot ioremap video memory " - "0x%x @ 0x%lx\n", - imacfb_fix.smem_len, imacfb_fix.smem_start); - err = -EIO; - goto err_unmap; - } - - printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, " - "using %dk, total %dk\n", - imacfb_fix.smem_start, info->screen_base, - size_remap/1024, size_total/1024); - printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n", - imacfb_defined.xres, imacfb_defined.yres, - imacfb_defined.bits_per_pixel, imacfb_fix.line_length, - screen_info.pages); - - imacfb_defined.xres_virtual = imacfb_defined.xres; - imacfb_defined.yres_virtual = imacfb_fix.smem_len / - imacfb_fix.line_length; - printk(KERN_INFO "imacfb: scrolling: redraw\n"); - imacfb_defined.yres_virtual = imacfb_defined.yres; - - /* some dummy values for timing to make fbset happy */ - imacfb_defined.pixclock = 10000000 / imacfb_defined.xres * - 1000 / imacfb_defined.yres; - imacfb_defined.left_margin = (imacfb_defined.xres / 8) & 0xf8; - imacfb_defined.hsync_len = (imacfb_defined.xres / 8) & 0xf8; - - imacfb_defined.red.offset = screen_info.red_pos; - imacfb_defined.red.length = screen_info.red_size; - imacfb_defined.green.offset = screen_info.green_pos; - imacfb_defined.green.length = screen_info.green_size; - imacfb_defined.blue.offset = screen_info.blue_pos; - imacfb_defined.blue.length = screen_info.blue_size; - imacfb_defined.transp.offset = screen_info.rsvd_pos; - imacfb_defined.transp.length = screen_info.rsvd_size; - - printk(KERN_INFO "imacfb: %s: " - "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", - "Truecolor", - screen_info.rsvd_size, - screen_info.red_size, - screen_info.green_size, - screen_info.blue_size, - screen_info.rsvd_pos, - screen_info.red_pos, - screen_info.green_pos, - screen_info.blue_pos); - - imacfb_fix.ypanstep = 0; - imacfb_fix.ywrapstep = 0; - - /* request failure does not faze us, as vgacon probably has this - * region already (FIXME) */ - request_region(0x3c0, 32, "imacfb"); - - info->fbops = &imacfb_ops; - info->var = imacfb_defined; - info->fix = imacfb_fix; - info->flags = FBINFO_FLAG_DEFAULT; - - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { - err = -ENOMEM; - goto err_unmap; - } - if (register_framebuffer(info)<0) { - err = -EINVAL; - goto err_fb_dealoc; - } - printk(KERN_INFO "fb%d: %s frame buffer device\n", - info->node, info->fix.id); - return 0; - -err_fb_dealoc: - fb_dealloc_cmap(&info->cmap); -err_unmap: - iounmap(info->screen_base); - framebuffer_release(info); -err_release_mem: - release_mem_region(imacfb_fix.smem_start, size_total); - return err; -} - -static struct platform_driver imacfb_driver = { - .probe = imacfb_probe, - .driver = { - .name = "imacfb", - }, -}; - -static struct platform_device imacfb_device = { - .name = "imacfb", -}; - -static int __init imacfb_init(void) -{ - int ret; - char *option = NULL; - - if (!efi_enabled) - return -ENODEV; - if (!dmi_check_system(dmi_system_table)) - return -ENODEV; - if (model == M_UNKNOWN) - return -ENODEV; - - if (fb_get_options("imacfb", &option)) - return -ENODEV; - - imacfb_setup(option); - ret = platform_driver_register(&imacfb_driver); - - if (!ret) { - ret = platform_device_register(&imacfb_device); - if (ret) - platform_driver_unregister(&imacfb_driver); - } - return ret; -} -module_init(imacfb_init); - -MODULE_LICENSE("GPL"); diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 3325fbd68ab..a50bea61480 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -12,9 +12,9 @@ #endif /*** Version/name ***/ -#define INTELFB_VERSION "0.9.5" +#define INTELFB_VERSION "0.9.6" #define INTELFB_MODULE_NAME "intelfb" -#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM" +#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/945GME/965G/965GM" /*** Debug/feature defines ***/ @@ -58,6 +58,7 @@ #define PCI_DEVICE_ID_INTEL_915GM 0x2592 #define PCI_DEVICE_ID_INTEL_945G 0x2772 #define PCI_DEVICE_ID_INTEL_945GM 0x27A2 +#define PCI_DEVICE_ID_INTEL_945GME 0x27AE #define PCI_DEVICE_ID_INTEL_965G 0x29A2 #define PCI_DEVICE_ID_INTEL_965GM 0x2A02 @@ -160,6 +161,7 @@ enum intel_chips { INTEL_915GM, INTEL_945G, INTEL_945GM, + INTEL_945GME, INTEL_965G, INTEL_965GM, }; @@ -363,6 +365,7 @@ struct intelfb_info { ((dinfo)->chipset == INTEL_915GM) || \ ((dinfo)->chipset == INTEL_945G) || \ ((dinfo)->chipset == INTEL_945GM) || \ + ((dinfo)->chipset == INTEL_945GME) || \ ((dinfo)->chipset == INTEL_965G) || \ ((dinfo)->chipset == INTEL_965GM)) diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index fcf9fadbf57..5d896b81f4e 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -171,6 +171,7 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo) /* has some LVDS + tv-out */ case INTEL_945G: case INTEL_945GM: + case INTEL_945GME: case INTEL_965G: case INTEL_965GM: /* SDVO ports have a single control bus - 2 devices */ diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index e44303f9bc5..a09e2364935 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -2,7 +2,7 @@ * intelfb * * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/ - * 945G/945GM/965G/965GM integrated graphics chips. + * 945G/945GM/945GME/965G/965GM integrated graphics chips. * * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org> * 2004 Sylvain Meyer @@ -102,6 +102,9 @@ * * 04/2008 - Version 0.9.5 * Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>) + * + * 08/2008 - Version 0.9.6 + * Add support for 945GME. (Phil Endecott <spam_from_intelfb@chezphil.org>) */ #include <linux/module.h> @@ -183,6 +186,7 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GME, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GME }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM }, { 0, } @@ -555,6 +559,7 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, (ent->device == PCI_DEVICE_ID_INTEL_915GM) || (ent->device == PCI_DEVICE_ID_INTEL_945G) || (ent->device == PCI_DEVICE_ID_INTEL_945GM) || + (ent->device == PCI_DEVICE_ID_INTEL_945GME) || (ent->device == PCI_DEVICE_ID_INTEL_965G) || (ent->device == PCI_DEVICE_ID_INTEL_965GM)) { diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 8e6d6a4db0a..8b26b27c2db 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -143,6 +143,12 @@ int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo) dinfo->mobile = 1; dinfo->pll_index = PLLS_I9xx; return 0; + case PCI_DEVICE_ID_INTEL_945GME: + dinfo->name = "Intel(R) 945GME"; + dinfo->chipset = INTEL_945GME; + dinfo->mobile = 1; + dinfo->pll_index = PLLS_I9xx; + return 0; case PCI_DEVICE_ID_INTEL_965G: dinfo->name = "Intel(R) 965G"; dinfo->chipset = INTEL_965G; @@ -186,6 +192,7 @@ int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size, case PCI_DEVICE_ID_INTEL_915GM: case PCI_DEVICE_ID_INTEL_945G: case PCI_DEVICE_ID_INTEL_945GM: + case PCI_DEVICE_ID_INTEL_945GME: case PCI_DEVICE_ID_INTEL_965G: case PCI_DEVICE_ID_INTEL_965GM: /* 915, 945 and 965 chipsets support a 256MB aperture. diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index c0213620279..8e7a275df50 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -1453,6 +1453,13 @@ static struct board { MGA_G100, &vbG100, "MGA-G100 (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200EV_PCI, 0xFF, + 0, 0, + DEVF_G200, + 230000, + MGA_G200, + &vbG200, + "MGA-G200eV (PCI)"}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF, 0, 0, DEVF_G200, @@ -2118,6 +2125,8 @@ static struct pci_device_id matroxfb_devices[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200EV_PCI, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c index afeed0611e3..df1f757a616 100644 --- a/drivers/video/metronomefb.c +++ b/drivers/video/metronomefb.c @@ -188,7 +188,7 @@ static int __devinit load_waveform(u8 *mem, size_t size, int m, int t, epd_frame_table[par->dt].wfm_size = user_wfm_size; if (size != epd_frame_table[par->dt].wfm_size) { - dev_err(dev, "Error: unexpected size %d != %d\n", size, + dev_err(dev, "Error: unexpected size %Zd != %d\n", size, epd_frame_table[par->dt].wfm_size); return -EINVAL; } diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 25172b2a2a9..bfb802d26d5 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -426,11 +426,11 @@ static void vgaHWProtect(int on) { unsigned char tmp; + tmp = vga_rseq(NULL, 0x01); if (on) { /* * Turn off screen and disable sequencer. */ - tmp = vga_rseq(NULL, 0x01); vga_wseq(NULL, 0x00, 0x01); /* Synchronous Reset */ vga_wseq(NULL, 0x01, tmp | 0x20); /* disable the display */ @@ -439,7 +439,6 @@ static void vgaHWProtect(int on) /* * Reenable sequencer, then turn on screen. */ - tmp = vga_rseq(NULL, 0x01); vga_wseq(NULL, 0x01, tmp & ~0x20); /* reenable display */ vga_wseq(NULL, 0x00, 0x03); /* clear synchronousreset */ @@ -558,14 +557,12 @@ neofb_open(struct fb_info *info, int user) { struct neofb_par *par = info->par; - mutex_lock(&par->open_lock); if (!par->ref_count) { memset(&par->state, 0, sizeof(struct vgastate)); par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS; save_vga(&par->state); } par->ref_count++; - mutex_unlock(&par->open_lock); return 0; } @@ -575,16 +572,13 @@ neofb_release(struct fb_info *info, int user) { struct neofb_par *par = info->par; - mutex_lock(&par->open_lock); - if (!par->ref_count) { - mutex_unlock(&par->open_lock); + if (!par->ref_count) return -EINVAL; - } + if (par->ref_count == 1) { restore_vga(&par->state); } par->ref_count--; - mutex_unlock(&par->open_lock); return 0; } @@ -648,10 +642,10 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->blue.msb_right = 0; var->transp.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; switch (var->bits_per_pixel) { case 8: /* PSEUDOCOLOUR, 256 */ - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 0; var->red.length = 8; var->green.offset = 0; @@ -661,8 +655,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) break; case 16: /* DIRECTCOLOUR, 64k */ - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; @@ -672,8 +664,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) break; case 24: /* TRUECOLOUR, 16m */ - var->transp.offset = 0; - var->transp.length = 0; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; @@ -704,8 +694,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if (vramlen > 4 * 1024 * 1024) vramlen = 4 * 1024 * 1024; - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; @@ -722,8 +710,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if it was possible. We should return -EINVAL, but I disagree */ if (var->yres_virtual < var->yres) var->yres = var->yres_virtual; - if (var->xres_virtual < var->xres) - var->xres = var->xres_virtual; if (var->xoffset + var->xres > var->xres_virtual) var->xoffset = var->xres_virtual - var->xres; if (var->yoffset + var->yres > var->yres_virtual) @@ -1186,8 +1172,11 @@ static int neofb_set_par(struct fb_info *info) return 0; } -static void neofb_update_start(struct fb_info *info, - struct fb_var_screeninfo *var) +/* + * Pan or Wrap the Display + */ +static int neofb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { struct neofb_par *par = info->par; struct vgastate *state = &par->state; @@ -1216,35 +1205,7 @@ static void neofb_update_start(struct fb_info *info, vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0))); neoLock(state); -} - -/* - * Pan or Wrap the Display - */ -static int neofb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - u_int y_bottom; - - y_bottom = var->yoffset; - - if (!(var->vmode & FB_VMODE_YWRAP)) - y_bottom += var->yres; - if (var->xoffset > (var->xres_virtual - var->xres)) - return -EINVAL; - if (y_bottom > info->var.yres_virtual) - return -EINVAL; - - neofb_update_start(info, var); - - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - - if (var->vmode & FB_VMODE_YWRAP) - info->var.vmode |= FB_VMODE_YWRAP; - else - info->var.vmode &= ~FB_VMODE_YWRAP; return 0; } @@ -1992,7 +1953,6 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st info->fix.accel = id->driver_data; - mutex_init(&par->open_lock); par->pci_burst = !nopciburst; par->lcd_stretch = !nostretch; par->libretto = libretto; diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c index 6a42c6a0cd9..4c4f7ee6d73 100644 --- a/drivers/video/omap/lcd_inn1610.c +++ b/drivers/video/omap/lcd_inn1610.c @@ -32,43 +32,43 @@ static int innovator1610_panel_init(struct lcd_panel *panel, { int r = 0; - if (omap_request_gpio(14)) { + if (gpio_request(14, "lcd_en0")) { pr_err(MODULE_NAME ": can't request GPIO 14\n"); r = -1; goto exit; } - if (omap_request_gpio(15)) { + if (gpio_request(15, "lcd_en1")) { pr_err(MODULE_NAME ": can't request GPIO 15\n"); - omap_free_gpio(14); + gpio_free(14); r = -1; goto exit; } /* configure GPIO(14, 15) as outputs */ - omap_set_gpio_direction(14, 0); - omap_set_gpio_direction(15, 0); + gpio_direction_output(14, 0); + gpio_direction_output(15, 0); exit: return r; } static void innovator1610_panel_cleanup(struct lcd_panel *panel) { - omap_free_gpio(15); - omap_free_gpio(14); + gpio_free(15); + gpio_free(14); } static int innovator1610_panel_enable(struct lcd_panel *panel) { /* set GPIO14 and GPIO15 high */ - omap_set_gpio_dataout(14, 1); - omap_set_gpio_dataout(15, 1); + gpio_set_value(14, 1); + gpio_set_value(15, 1); return 0; } static void innovator1610_panel_disable(struct lcd_panel *panel) { /* set GPIO13, GPIO14 and GPIO15 low */ - omap_set_gpio_dataout(14, 0); - omap_set_gpio_dataout(15, 0); + gpio_set_value(14, 0); + gpio_set_value(15, 0); } static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel) diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c index a4a725f427a..379c96d36da 100644 --- a/drivers/video/omap/lcd_osk.c +++ b/drivers/video/omap/lcd_osk.c @@ -29,6 +29,7 @@ static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) { + /* gpio2 was allocated in board init */ return 0; } @@ -47,11 +48,8 @@ static int osk_panel_enable(struct lcd_panel *panel) /* Set PWL level */ omap_writeb(0xFF, OMAP_PWL_ENABLE); - /* configure GPIO2 as output */ - omap_set_gpio_direction(2, 0); - - /* set GPIO2 high */ - omap_set_gpio_dataout(2, 1); + /* set GPIO2 high (lcd power enabled) */ + gpio_set_value(2, 1); return 0; } @@ -65,7 +63,7 @@ static void osk_panel_disable(struct lcd_panel *panel) omap_writeb(0x00, OMAP_PWL_CLK_ENABLE); /* set GPIO2 low */ - omap_set_gpio_dataout(2, 0); + gpio_set_value(2, 0); } static unsigned long osk_panel_get_caps(struct lcd_panel *panel) diff --git a/drivers/video/omap/lcd_sx1.c b/drivers/video/omap/lcd_sx1.c index caa6a896cb8..e55de201b8f 100644 --- a/drivers/video/omap/lcd_sx1.c +++ b/drivers/video/omap/lcd_sx1.c @@ -81,21 +81,21 @@ static void epson_sendbyte(int flag, unsigned char byte) int i, shifter = 0x80; if (!flag) - omap_set_gpio_dataout(_A_LCD_SSC_A0, 0); + gpio_set_value(_A_LCD_SSC_A0, 0); mdelay(2); - omap_set_gpio_dataout(A_LCD_SSC_RD, 1); + gpio_set_value(A_LCD_SSC_RD, 1); - omap_set_gpio_dataout(A_LCD_SSC_SD, flag); + gpio_set_value(A_LCD_SSC_SD, flag); OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200); OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202); for (i = 0; i < 8; i++) { OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200); - omap_set_gpio_dataout(A_LCD_SSC_SD, shifter & byte); + gpio_set_value(A_LCD_SSC_SD, shifter & byte); OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202); shifter >>= 1; } - omap_set_gpio_dataout(_A_LCD_SSC_A0, 1); + gpio_set_value(_A_LCD_SSC_A0, 1); } static void init_system(void) @@ -107,25 +107,18 @@ static void init_system(void) static void setup_GPIO(void) { /* new wave */ - omap_request_gpio(A_LCD_SSC_RD); - omap_request_gpio(A_LCD_SSC_SD); - omap_request_gpio(_A_LCD_RESET); - omap_request_gpio(_A_LCD_SSC_CS); - omap_request_gpio(_A_LCD_SSC_A0); - - /* set all GPIOs to output */ - omap_set_gpio_direction(A_LCD_SSC_RD, 0); - omap_set_gpio_direction(A_LCD_SSC_SD, 0); - omap_set_gpio_direction(_A_LCD_RESET, 0); - omap_set_gpio_direction(_A_LCD_SSC_CS, 0); - omap_set_gpio_direction(_A_LCD_SSC_A0, 0); - - /* set GPIO data */ - omap_set_gpio_dataout(A_LCD_SSC_RD, 1); - omap_set_gpio_dataout(A_LCD_SSC_SD, 0); - omap_set_gpio_dataout(_A_LCD_RESET, 0); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_A0, 1); + gpio_request(A_LCD_SSC_RD, "lcd_ssc_rd"); + gpio_request(A_LCD_SSC_SD, "lcd_ssc_sd"); + gpio_request(_A_LCD_RESET, "lcd_reset"); + gpio_request(_A_LCD_SSC_CS, "lcd_ssc_cs"); + gpio_request(_A_LCD_SSC_A0, "lcd_ssc_a0"); + + /* set GPIOs to output, with initial data */ + gpio_direction_output(A_LCD_SSC_RD, 1); + gpio_direction_output(A_LCD_SSC_SD, 0); + gpio_direction_output(_A_LCD_RESET, 0); + gpio_direction_output(_A_LCD_SSC_CS, 1); + gpio_direction_output(_A_LCD_SSC_A0, 1); } static void display_init(void) @@ -139,61 +132,61 @@ static void display_init(void) mdelay(2); /* reset LCD */ - omap_set_gpio_dataout(A_LCD_SSC_SD, 1); + gpio_set_value(A_LCD_SSC_SD, 1); epson_sendbyte(0, 0x25); - omap_set_gpio_dataout(_A_LCD_RESET, 0); + gpio_set_value(_A_LCD_RESET, 0); mdelay(10); - omap_set_gpio_dataout(_A_LCD_RESET, 1); + gpio_set_value(_A_LCD_RESET, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 1); mdelay(2); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD, phase 1 */ epson_sendbyte(0, 0xCA); for (i = 0; i < 10; i++) epson_sendbyte(1, INIT_1[i]); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 2 */ epson_sendbyte(0, 0xCB); for (i = 0; i < 125; i++) epson_sendbyte(1, INIT_2[i]); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 2a */ epson_sendbyte(0, 0xCC); for (i = 0; i < 14; i++) epson_sendbyte(1, INIT_3[i]); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 3 */ epson_sendbyte(0, 0xBC); epson_sendbyte(1, 0x08); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 4 */ epson_sendbyte(0, 0x07); epson_sendbyte(1, 0x05); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 5 */ epson_sendbyte(0, 0x94); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 6 */ epson_sendbyte(0, 0xC6); epson_sendbyte(1, 0x80); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 1); mdelay(100); /* used to be 1000 */ - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 7 */ epson_sendbyte(0, 0x16); @@ -201,8 +194,8 @@ static void display_init(void) epson_sendbyte(1, 0x00); epson_sendbyte(1, 0xB1); epson_sendbyte(1, 0x00); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 8 */ epson_sendbyte(0, 0x76); @@ -210,12 +203,12 @@ static void display_init(void) epson_sendbyte(1, 0x00); epson_sendbyte(1, 0xDB); epson_sendbyte(1, 0x00); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 0); /* init LCD phase 9 */ epson_sendbyte(0, 0xAF); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 1); } static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) @@ -231,18 +224,18 @@ static void sx1_panel_disable(struct lcd_panel *panel) { printk(KERN_INFO "SX1: LCD panel disable\n"); sx1_setmmipower(0); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 1); epson_sendbyte(0, 0x25); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 0); epson_sendbyte(0, 0xAE); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 1); mdelay(100); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 0); + gpio_set_value(_A_LCD_SSC_CS, 0); epson_sendbyte(0, 0x95); - omap_set_gpio_dataout(_A_LCD_SSC_CS, 1); + gpio_set_value(_A_LCD_SSC_CS, 1); } static int sx1_panel_enable(struct lcd_panel *panel) diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index b829dc7c5ed..a7b01d2724b 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -50,6 +50,11 @@ #define dbg(fmt, args...) do { } while (0) #endif +static const int __devinitconst s1d13xxxfb_revisions[] = { + S1D13506_CHIP_REV, /* Rev.4 on HP Jornada 7xx S1D13506 */ + S1D13806_CHIP_REV, /* Rev.7 on .. */ +}; + /* * Here we define the default struct fb_fix_screeninfo */ @@ -538,6 +543,7 @@ s1d13xxxfb_probe(struct platform_device *pdev) struct fb_info *info; struct s1d13xxxfb_pdata *pdata = NULL; int ret = 0; + int i; u8 revision; dbg("probe called: device is %p\n", pdev); @@ -607,10 +613,19 @@ s1d13xxxfb_probe(struct platform_device *pdev) goto bail; } - revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE); - if ((revision >> 2) != S1D_CHIP_REV) { - printk(KERN_INFO PFX "chip not found: %i\n", (revision >> 2)); - ret = -ENODEV; + revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2; + + ret = -ENODEV; + + for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_revisions); i++) { + if (revision == s1d13xxxfb_revisions[i]) + ret = 0; + } + + if (!ret) + printk(KERN_INFO PFX "chip revision %i\n", revision); + else { + printk(KERN_INFO PFX "unknown chip revision %i\n", revision); goto bail; } diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 4599a4385bc..14bd3f3680b 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1195,57 +1195,58 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, return -ENOMEM; default_par = info->par; + info->fix = tdfx_fix; /* Configure the default fb_fix_screeninfo first */ switch (pdev->device) { case PCI_DEVICE_ID_3DFX_BANSHEE: - strcpy(tdfx_fix.id, "3Dfx Banshee"); + strcpy(info->fix.id, "3Dfx Banshee"); default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK; break; case PCI_DEVICE_ID_3DFX_VOODOO3: - strcpy(tdfx_fix.id, "3Dfx Voodoo3"); + strcpy(info->fix.id, "3Dfx Voodoo3"); default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK; break; case PCI_DEVICE_ID_3DFX_VOODOO5: - strcpy(tdfx_fix.id, "3Dfx Voodoo5"); + strcpy(info->fix.id, "3Dfx Voodoo5"); default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK; break; } - tdfx_fix.mmio_start = pci_resource_start(pdev, 0); - tdfx_fix.mmio_len = pci_resource_len(pdev, 0); - if (!request_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len, + info->fix.mmio_start = pci_resource_start(pdev, 0); + info->fix.mmio_len = pci_resource_len(pdev, 0); + if (!request_mem_region(info->fix.mmio_start, info->fix.mmio_len, "tdfx regbase")) { printk(KERN_ERR "tdfxfb: Can't reserve regbase\n"); goto out_err; } default_par->regbase_virt = - ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len); + ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); if (!default_par->regbase_virt) { printk(KERN_ERR "fb: Can't remap %s register area.\n", - tdfx_fix.id); + info->fix.id); goto out_err_regbase; } - tdfx_fix.smem_start = pci_resource_start(pdev, 1); - tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device); - if (!tdfx_fix.smem_len) { - printk(KERN_ERR "fb: Can't count %s memory.\n", tdfx_fix.id); + info->fix.smem_start = pci_resource_start(pdev, 1); + info->fix.smem_len = do_lfb_size(default_par, pdev->device); + if (!info->fix.smem_len) { + printk(KERN_ERR "fb: Can't count %s memory.\n", info->fix.id); goto out_err_regbase; } - if (!request_mem_region(tdfx_fix.smem_start, + if (!request_mem_region(info->fix.smem_start, pci_resource_len(pdev, 1), "tdfx smem")) { printk(KERN_ERR "tdfxfb: Can't reserve smem\n"); goto out_err_regbase; } - info->screen_base = ioremap_nocache(tdfx_fix.smem_start, - tdfx_fix.smem_len); + info->screen_base = ioremap_nocache(info->fix.smem_start, + info->fix.smem_len); if (!info->screen_base) { printk(KERN_ERR "fb: Can't remap %s framebuffer.\n", - tdfx_fix.id); + info->fix.id); goto out_err_screenbase; } @@ -1257,20 +1258,19 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, goto out_err_screenbase; } - printk(KERN_INFO "fb: %s memory = %dK\n", tdfx_fix.id, - tdfx_fix.smem_len >> 10); + printk(KERN_INFO "fb: %s memory = %dK\n", info->fix.id, + info->fix.smem_len >> 10); default_par->mtrr_handle = -1; if (!nomtrr) default_par->mtrr_handle = - mtrr_add(tdfx_fix.smem_start, tdfx_fix.smem_len, + mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); - tdfx_fix.ypanstep = nopan ? 0 : 1; - tdfx_fix.ywrapstep = nowrap ? 0 : 1; + info->fix.ypanstep = nopan ? 0 : 1; + info->fix.ywrapstep = nowrap ? 0 : 1; info->fbops = &tdfxfb_ops; - info->fix = tdfx_fix; info->pseudo_palette = default_par->palette; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; #ifdef CONFIG_FB_3DFX_ACCEL @@ -1323,14 +1323,14 @@ out_err_iobase: out_err_screenbase: if (info->screen_base) iounmap(info->screen_base); - release_mem_region(tdfx_fix.smem_start, pci_resource_len(pdev, 1)); + release_mem_region(info->fix.smem_start, pci_resource_len(pdev, 1)); out_err_regbase: /* * Cleanup after anything that was remapped/allocated. */ if (default_par->regbase_virt) iounmap(default_par->regbase_virt); - release_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len); + release_mem_region(info->fix.mmio_start, info->fix.mmio_len); out_err: framebuffer_release(info); return -ENXIO; diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c new file mode 100644 index 00000000000..2a380011e9b --- /dev/null +++ b/drivers/video/tmiofb.c @@ -0,0 +1,1050 @@ +/* + * Frame Buffer Device for Toshiba Mobile IO(TMIO) controller + * + * Copyright(C) 2005-2006 Chris Humbert + * Copyright(C) 2005 Dirk Opfer + * Copytight(C) 2007,2008 Dmitry Baryshkov + * + * Based on: + * drivers/video/w100fb.c + * code written by Sharp/Lineo for 2.4 kernels + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/fb.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +/* Why should fb driver call console functions? because acquire_console_sem() */ +#include <linux/console.h> +#include <linux/mfd/core.h> +#include <linux/mfd/tmio.h> +#include <linux/uaccess.h> + +/* + * accelerator commands + */ +#define TMIOFB_ACC_CSADR(x) (0x00000000 | ((x) & 0x001ffffe)) +#define TMIOFB_ACC_CHPIX(x) (0x01000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_CVPIX(x) (0x02000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_PSADR(x) (0x03000000 | ((x) & 0x00fffffe)) +#define TMIOFB_ACC_PHPIX(x) (0x04000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_PVPIX(x) (0x05000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_PHOFS(x) (0x06000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_PVOFS(x) (0x07000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_POADR(x) (0x08000000 | ((x) & 0x00fffffe)) +#define TMIOFB_ACC_RSTR(x) (0x09000000 | ((x) & 0x000000ff)) +#define TMIOFB_ACC_TCLOR(x) (0x0A000000 | ((x) & 0x0000ffff)) +#define TMIOFB_ACC_FILL(x) (0x0B000000 | ((x) & 0x0000ffff)) +#define TMIOFB_ACC_DSADR(x) (0x0C000000 | ((x) & 0x00fffffe)) +#define TMIOFB_ACC_SSADR(x) (0x0D000000 | ((x) & 0x00fffffe)) +#define TMIOFB_ACC_DHPIX(x) (0x0E000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_DVPIX(x) (0x0F000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_SHPIX(x) (0x10000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_SVPIX(x) (0x11000000 | ((x) & 0x000003ff)) +#define TMIOFB_ACC_LBINI(x) (0x12000000 | ((x) & 0x0000ffff)) +#define TMIOFB_ACC_LBK2(x) (0x13000000 | ((x) & 0x0000ffff)) +#define TMIOFB_ACC_SHBINI(x) (0x14000000 | ((x) & 0x0000ffff)) +#define TMIOFB_ACC_SHBK2(x) (0x15000000 | ((x) & 0x0000ffff)) +#define TMIOFB_ACC_SVBINI(x) (0x16000000 | ((x) & 0x0000ffff)) +#define TMIOFB_ACC_SVBK2(x) (0x17000000 | ((x) & 0x0000ffff)) + +#define TMIOFB_ACC_CMGO 0x20000000 +#define TMIOFB_ACC_CMGO_CEND 0x00000001 +#define TMIOFB_ACC_CMGO_INT 0x00000002 +#define TMIOFB_ACC_CMGO_CMOD 0x00000010 +#define TMIOFB_ACC_CMGO_CDVRV 0x00000020 +#define TMIOFB_ACC_CMGO_CDHRV 0x00000040 +#define TMIOFB_ACC_CMGO_RUND 0x00008000 +#define TMIOFB_ACC_SCGO 0x21000000 +#define TMIOFB_ACC_SCGO_CEND 0x00000001 +#define TMIOFB_ACC_SCGO_INT 0x00000002 +#define TMIOFB_ACC_SCGO_ROP3 0x00000004 +#define TMIOFB_ACC_SCGO_TRNS 0x00000008 +#define TMIOFB_ACC_SCGO_DVRV 0x00000010 +#define TMIOFB_ACC_SCGO_DHRV 0x00000020 +#define TMIOFB_ACC_SCGO_SVRV 0x00000040 +#define TMIOFB_ACC_SCGO_SHRV 0x00000080 +#define TMIOFB_ACC_SCGO_DSTXY 0x00008000 +#define TMIOFB_ACC_SBGO 0x22000000 +#define TMIOFB_ACC_SBGO_CEND 0x00000001 +#define TMIOFB_ACC_SBGO_INT 0x00000002 +#define TMIOFB_ACC_SBGO_DVRV 0x00000010 +#define TMIOFB_ACC_SBGO_DHRV 0x00000020 +#define TMIOFB_ACC_SBGO_SVRV 0x00000040 +#define TMIOFB_ACC_SBGO_SHRV 0x00000080 +#define TMIOFB_ACC_SBGO_SBMD 0x00000100 +#define TMIOFB_ACC_FLGO 0x23000000 +#define TMIOFB_ACC_FLGO_CEND 0x00000001 +#define TMIOFB_ACC_FLGO_INT 0x00000002 +#define TMIOFB_ACC_FLGO_ROP3 0x00000004 +#define TMIOFB_ACC_LDGO 0x24000000 +#define TMIOFB_ACC_LDGO_CEND 0x00000001 +#define TMIOFB_ACC_LDGO_INT 0x00000002 +#define TMIOFB_ACC_LDGO_ROP3 0x00000004 +#define TMIOFB_ACC_LDGO_ENDPX 0x00000008 +#define TMIOFB_ACC_LDGO_LVRV 0x00000010 +#define TMIOFB_ACC_LDGO_LHRV 0x00000020 +#define TMIOFB_ACC_LDGO_LDMOD 0x00000040 + +/* a FIFO is always allocated, even if acceleration is not used */ +#define TMIOFB_FIFO_SIZE 512 + +/* + * LCD Host Controller Configuration Register + * + * This iomem area supports only 16-bit IO. + */ +#define CCR_CMD 0x04 /* Command */ +#define CCR_REVID 0x08 /* Revision ID */ +#define CCR_BASEL 0x10 /* LCD Control Reg Base Addr Low */ +#define CCR_BASEH 0x12 /* LCD Control Reg Base Addr High */ +#define CCR_UGCC 0x40 /* Unified Gated Clock Control */ +#define CCR_GCC 0x42 /* Gated Clock Control */ +#define CCR_USC 0x50 /* Unified Software Clear */ +#define CCR_VRAMRTC 0x60 /* VRAM Timing Control */ + /* 0x61 VRAM Refresh Control */ +#define CCR_VRAMSAC 0x62 /* VRAM Access Control */ + /* 0x63 VRAM Status */ +#define CCR_VRAMBC 0x64 /* VRAM Block Control */ + +/* + * LCD Control Register + * + * This iomem area supports only 16-bit IO. + */ +#define LCR_UIS 0x000 /* Unified Interrupt Status */ +#define LCR_VHPN 0x008 /* VRAM Horizontal Pixel Number */ +#define LCR_CFSAL 0x00a /* Command FIFO Start Address Low */ +#define LCR_CFSAH 0x00c /* Command FIFO Start Address High */ +#define LCR_CFS 0x00e /* Command FIFO Size */ +#define LCR_CFWS 0x010 /* Command FIFO Writeable Size */ +#define LCR_BBIE 0x012 /* BitBLT Interrupt Enable */ +#define LCR_BBISC 0x014 /* BitBLT Interrupt Status and Clear */ +#define LCR_CCS 0x016 /* Command Count Status */ +#define LCR_BBES 0x018 /* BitBLT Execution Status */ +#define LCR_CMDL 0x01c /* Command Low */ +#define LCR_CMDH 0x01e /* Command High */ +#define LCR_CFC 0x022 /* Command FIFO Clear */ +#define LCR_CCIFC 0x024 /* CMOS Camera IF Control */ +#define LCR_HWT 0x026 /* Hardware Test */ +#define LCR_LCDCCRC 0x100 /* LCDC Clock and Reset Control */ +#define LCR_LCDCC 0x102 /* LCDC Control */ +#define LCR_LCDCOPC 0x104 /* LCDC Output Pin Control */ +#define LCR_LCDIS 0x108 /* LCD Interrupt Status */ +#define LCR_LCDIM 0x10a /* LCD Interrupt Mask */ +#define LCR_LCDIE 0x10c /* LCD Interrupt Enable */ +#define LCR_GDSAL 0x122 /* Graphics Display Start Address Low */ +#define LCR_GDSAH 0x124 /* Graphics Display Start Address High */ +#define LCR_VHPCL 0x12a /* VRAM Horizontal Pixel Count Low */ +#define LCR_VHPCH 0x12c /* VRAM Horizontal Pixel Count High */ +#define LCR_GM 0x12e /* Graphic Mode(VRAM access enable) */ +#define LCR_HT 0x140 /* Horizontal Total */ +#define LCR_HDS 0x142 /* Horizontal Display Start */ +#define LCR_HSS 0x144 /* H-Sync Start */ +#define LCR_HSE 0x146 /* H-Sync End */ +#define LCR_HNP 0x14c /* Horizontal Number of Pixels */ +#define LCR_VT 0x150 /* Vertical Total */ +#define LCR_VDS 0x152 /* Vertical Display Start */ +#define LCR_VSS 0x154 /* V-Sync Start */ +#define LCR_VSE 0x156 /* V-Sync End */ +#define LCR_CDLN 0x160 /* Current Display Line Number */ +#define LCR_ILN 0x162 /* Interrupt Line Number */ +#define LCR_SP 0x164 /* Sync Polarity */ +#define LCR_MISC 0x166 /* MISC(RGB565 mode) */ +#define LCR_VIHSS 0x16a /* Video Interface H-Sync Start */ +#define LCR_VIVS 0x16c /* Video Interface Vertical Start */ +#define LCR_VIVE 0x16e /* Video Interface Vertical End */ +#define LCR_VIVSS 0x170 /* Video Interface V-Sync Start */ +#define LCR_VCCIS 0x17e /* Video / CMOS Camera Interface Select */ +#define LCR_VIDWSAL 0x180 /* VI Data Write Start Address Low */ +#define LCR_VIDWSAH 0x182 /* VI Data Write Start Address High */ +#define LCR_VIDRSAL 0x184 /* VI Data Read Start Address Low */ +#define LCR_VIDRSAH 0x186 /* VI Data Read Start Address High */ +#define LCR_VIPDDST 0x188 /* VI Picture Data Display Start Timing */ +#define LCR_VIPDDET 0x186 /* VI Picture Data Display End Timing */ +#define LCR_VIE 0x18c /* Video Interface Enable */ +#define LCR_VCS 0x18e /* Video/Camera Select */ +#define LCR_VPHWC 0x194 /* Video Picture Horizontal Wait Count */ +#define LCR_VPHS 0x196 /* Video Picture Horizontal Size */ +#define LCR_VPVWC 0x198 /* Video Picture Vertical Wait Count */ +#define LCR_VPVS 0x19a /* Video Picture Vertical Size */ +#define LCR_PLHPIX 0x1a0 /* PLHPIX */ +#define LCR_XS 0x1a2 /* XStart */ +#define LCR_XCKHW 0x1a4 /* XCK High Width */ +#define LCR_STHS 0x1a8 /* STH Start */ +#define LCR_VT2 0x1aa /* Vertical Total */ +#define LCR_YCKSW 0x1ac /* YCK Start Wait */ +#define LCR_YSTS 0x1ae /* YST Start */ +#define LCR_PPOLS 0x1b0 /* #PPOL Start */ +#define LCR_PRECW 0x1b2 /* PREC Width */ +#define LCR_VCLKHW 0x1b4 /* VCLK High Width */ +#define LCR_OC 0x1b6 /* Output Control */ + +static char *mode_option __devinitdata; + +struct tmiofb_par { + u32 pseudo_palette[16]; + +#ifdef CONFIG_FB_TMIO_ACCELL + wait_queue_head_t wait_acc; + bool use_polling; +#endif + + void __iomem *ccr; + void __iomem *lcr; +}; + +/*--------------------------------------------------------------------------*/ + +/* + * reasons for an interrupt: + * uis bbisc lcdis + * 0100 0001 accelerator command completed + * 2000 0001 vsync start + * 2000 0002 display start + * 2000 0004 line number match(0x1ff mask???) + */ +static irqreturn_t tmiofb_irq(int irq, void *__info) +{ + struct fb_info *info = __info; + struct tmiofb_par *par = info->par; + unsigned int bbisc = tmio_ioread16(par->lcr + LCR_BBISC); + + + /* + * We were in polling mode and now we got correct irq. + * Switch back to IRQ-based sync of command FIFO + */ + if (unlikely(par->use_polling && irq != -1)) { + printk(KERN_INFO "tmiofb: switching to waitq\n"); + par->use_polling = false; + } + + tmio_iowrite16(bbisc, par->lcr + LCR_BBISC); + +#ifdef CONFIG_FB_TMIO_ACCELL + if (bbisc & 1) + wake_up(&par->wait_acc); +#endif + + return IRQ_HANDLED; +} + + +/*--------------------------------------------------------------------------*/ + + +/* + * Turns off the LCD controller and LCD host controller. + */ +static int tmiofb_hw_stop(struct platform_device *dev) +{ + struct mfd_cell *cell = dev->dev.platform_data; + struct tmio_fb_data *data = cell->driver_data; + struct fb_info *info = platform_get_drvdata(dev); + struct tmiofb_par *par = info->par; + + tmio_iowrite16(0, par->ccr + CCR_UGCC); + tmio_iowrite16(0, par->lcr + LCR_GM); + data->lcd_set_power(dev, 0); + tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC); + + return 0; +} + +/* + * Initializes the LCD host controller. + */ +static int tmiofb_hw_init(struct platform_device *dev) +{ + struct mfd_cell *cell = dev->dev.platform_data; + struct fb_info *info = platform_get_drvdata(dev); + struct tmiofb_par *par = info->par; + const struct resource *nlcr = &cell->resources[0]; + const struct resource *vram = &cell->resources[2]; + unsigned long base; + + if (nlcr == NULL || vram == NULL) + return -EINVAL; + + base = nlcr->start; + + tmio_iowrite16(0x003a, par->ccr + CCR_UGCC); + tmio_iowrite16(0x003a, par->ccr + CCR_GCC); + tmio_iowrite16(0x3f00, par->ccr + CCR_USC); + + msleep(2); /* wait for device to settle */ + + tmio_iowrite16(0x0000, par->ccr + CCR_USC); + tmio_iowrite16(base >> 16, par->ccr + CCR_BASEH); + tmio_iowrite16(base, par->ccr + CCR_BASEL); + tmio_iowrite16(0x0002, par->ccr + CCR_CMD); /* base address enable */ + tmio_iowrite16(0x40a8, par->ccr + CCR_VRAMRTC); /* VRAMRC, VRAMTC */ + tmio_iowrite16(0x0018, par->ccr + CCR_VRAMSAC); /* VRAMSTS, VRAMAC */ + tmio_iowrite16(0x0002, par->ccr + CCR_VRAMBC); + msleep(2); /* wait for device to settle */ + tmio_iowrite16(0x000b, par->ccr + CCR_VRAMBC); + + base = vram->start + info->screen_size; + tmio_iowrite16(base >> 16, par->lcr + LCR_CFSAH); + tmio_iowrite16(base, par->lcr + LCR_CFSAL); + tmio_iowrite16(TMIOFB_FIFO_SIZE - 1, par->lcr + LCR_CFS); + tmio_iowrite16(1, par->lcr + LCR_CFC); + tmio_iowrite16(1, par->lcr + LCR_BBIE); + tmio_iowrite16(0, par->lcr + LCR_CFWS); + + return 0; +} + +/* + * Sets the LCD controller's output resolution and pixel clock + */ +static void tmiofb_hw_mode(struct platform_device *dev) +{ + struct mfd_cell *cell = dev->dev.platform_data; + struct tmio_fb_data *data = cell->driver_data; + struct fb_info *info = platform_get_drvdata(dev); + struct fb_videomode *mode = info->mode; + struct tmiofb_par *par = info->par; + unsigned int i; + + tmio_iowrite16(0, par->lcr + LCR_GM); + data->lcd_set_power(dev, 0); + tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC); + data->lcd_mode(dev, mode); + data->lcd_set_power(dev, 1); + + tmio_iowrite16(info->fix.line_length, par->lcr + LCR_VHPN); + tmio_iowrite16(0, par->lcr + LCR_GDSAH); + tmio_iowrite16(0, par->lcr + LCR_GDSAL); + tmio_iowrite16(info->fix.line_length >> 16, par->lcr + LCR_VHPCH); + tmio_iowrite16(info->fix.line_length, par->lcr + LCR_VHPCL); + tmio_iowrite16(i = 0, par->lcr + LCR_HSS); + tmio_iowrite16(i += mode->hsync_len, par->lcr + LCR_HSE); + tmio_iowrite16(i += mode->left_margin, par->lcr + LCR_HDS); + tmio_iowrite16(i += mode->xres + mode->right_margin, par->lcr + LCR_HT); + tmio_iowrite16(mode->xres, par->lcr + LCR_HNP); + tmio_iowrite16(i = 0, par->lcr + LCR_VSS); + tmio_iowrite16(i += mode->vsync_len, par->lcr + LCR_VSE); + tmio_iowrite16(i += mode->upper_margin, par->lcr + LCR_VDS); + tmio_iowrite16(i += mode->yres, par->lcr + LCR_ILN); + tmio_iowrite16(i += mode->lower_margin, par->lcr + LCR_VT); + tmio_iowrite16(3, par->lcr + LCR_MISC); /* RGB565 mode */ + tmio_iowrite16(1, par->lcr + LCR_GM); /* VRAM enable */ + tmio_iowrite16(0x4007, par->lcr + LCR_LCDCC); + tmio_iowrite16(3, par->lcr + LCR_SP); /* sync polarity */ + + tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC); + msleep(5); /* wait for device to settle */ + tmio_iowrite16(0x0014, par->lcr + LCR_LCDCCRC); /* STOP_CKP */ + msleep(5); /* wait for device to settle */ + tmio_iowrite16(0x0015, par->lcr + LCR_LCDCCRC); /* STOP_CKP|SOFT_RESET*/ + tmio_iowrite16(0xfffa, par->lcr + LCR_VCS); +} + +/*--------------------------------------------------------------------------*/ + +#ifdef CONFIG_FB_TMIO_ACCELL +static int __must_check +tmiofb_acc_wait(struct fb_info *info, unsigned int ccs) +{ + struct tmiofb_par *par = info->par; + /* + * This code can be called whith interrupts disabled. + * So instead of relaying on irq to trigger the event, + * poll the state till the necessary command is executed. + */ + if (irqs_disabled() || par->use_polling) { + int i = 0; + while (tmio_ioread16(par->lcr + LCR_CCS) > ccs) { + udelay(1); + i++; + if (i > 10000) { + pr_err("tmiofb: timeout waiting for %d\n", + ccs); + return -ETIMEDOUT; + } + tmiofb_irq(-1, info); + } + } else { + if (!wait_event_interruptible_timeout(par->wait_acc, + tmio_ioread16(par->lcr + LCR_CCS) <= ccs, + 1000)) { + pr_err("tmiofb: timeout waiting for %d\n", ccs); + return -ETIMEDOUT; + } + } + + return 0; +} + +/* + * Writes an accelerator command to the accelerator's FIFO. + */ +static int +tmiofb_acc_write(struct fb_info *info, const u32 *cmd, unsigned int count) +{ + struct tmiofb_par *par = info->par; + int ret; + + ret = tmiofb_acc_wait(info, TMIOFB_FIFO_SIZE - count); + if (ret) + return ret; + + for (; count; count--, cmd++) { + tmio_iowrite16(*cmd >> 16, par->lcr + LCR_CMDH); + tmio_iowrite16(*cmd, par->lcr + LCR_CMDL); + } + + return ret; +} + +/* + * Wait for the accelerator to finish its operations before writing + * to the framebuffer for consistent display output. + */ +static int tmiofb_sync(struct fb_info *fbi) +{ + struct tmiofb_par *par = fbi->par; + + int ret; + int i = 0; + + ret = tmiofb_acc_wait(fbi, 0); + + while (tmio_ioread16(par->lcr + LCR_BBES) & 2) { /* blit active */ + udelay(1); + i++ ; + if (i > 10000) { + printk(KERN_ERR "timeout waiting for blit to end!\n"); + return -ETIMEDOUT; + } + } + + return ret; +} + +static void +tmiofb_fillrect(struct fb_info *fbi, const struct fb_fillrect *rect) +{ + const u32 cmd[] = { + TMIOFB_ACC_DSADR((rect->dy * fbi->mode->xres + rect->dx) * 2), + TMIOFB_ACC_DHPIX(rect->width - 1), + TMIOFB_ACC_DVPIX(rect->height - 1), + TMIOFB_ACC_FILL(rect->color), + TMIOFB_ACC_FLGO, + }; + + if (fbi->state != FBINFO_STATE_RUNNING || + fbi->flags & FBINFO_HWACCEL_DISABLED) { + cfb_fillrect(fbi, rect); + return; + } + + tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd)); +} + +static void +tmiofb_copyarea(struct fb_info *fbi, const struct fb_copyarea *area) +{ + const u32 cmd[] = { + TMIOFB_ACC_DSADR((area->dy * fbi->mode->xres + area->dx) * 2), + TMIOFB_ACC_DHPIX(area->width - 1), + TMIOFB_ACC_DVPIX(area->height - 1), + TMIOFB_ACC_SSADR((area->sy * fbi->mode->xres + area->sx) * 2), + TMIOFB_ACC_SCGO, + }; + + if (fbi->state != FBINFO_STATE_RUNNING || + fbi->flags & FBINFO_HWACCEL_DISABLED) { + cfb_copyarea(fbi, area); + return; + } + + tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd)); +} +#endif + +static void tmiofb_clearscreen(struct fb_info *info) +{ + const struct fb_fillrect rect = { + .dx = 0, + .dy = 0, + .width = info->mode->xres, + .height = info->mode->yres, + .color = 0, + .rop = ROP_COPY, + }; + + info->fbops->fb_fillrect(info, &rect); +} + +static int tmiofb_vblank(struct fb_info *fbi, struct fb_vblank *vblank) +{ + struct tmiofb_par *par = fbi->par; + struct fb_videomode *mode = fbi->mode; + unsigned int vcount = tmio_ioread16(par->lcr + LCR_CDLN); + unsigned int vds = mode->vsync_len + mode->upper_margin; + + vblank->vcount = vcount; + vblank->flags = FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_VCOUNT + | FB_VBLANK_HAVE_VSYNC; + + if (vcount < mode->vsync_len) + vblank->flags |= FB_VBLANK_VSYNCING; + + if (vcount < vds || vcount > vds + mode->yres) + vblank->flags |= FB_VBLANK_VBLANKING; + + return 0; +} + + +static int tmiofb_ioctl(struct fb_info *fbi, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case FBIOGET_VBLANK: { + struct fb_vblank vblank = {0}; + void __user *argp = (void __user *) arg; + + tmiofb_vblank(fbi, &vblank); + if (copy_to_user(argp, &vblank, sizeof vblank)) + return -EFAULT; + return 0; + } + +#ifdef CONFIG_FB_TMIO_ACCELL + case FBIO_TMIO_ACC_SYNC: + tmiofb_sync(fbi); + return 0; + + case FBIO_TMIO_ACC_WRITE: { + u32 __user *argp = (void __user *) arg; + u32 len; + u32 acc[16]; + + if (get_user(len, argp)) + return -EFAULT; + if (len > ARRAY_SIZE(acc)) + return -EINVAL; + if (copy_from_user(acc, argp + 1, sizeof(u32) * len)) + return -EFAULT; + + return tmiofb_acc_write(fbi, acc, len); + } +#endif + } + + return -ENOTTY; +} + +/*--------------------------------------------------------------------------*/ + +/* Select the smallest mode that allows the desired resolution to be + * displayed. If desired, the x and y parameters can be rounded up to + * match the selected mode. + */ +static struct fb_videomode * +tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var) +{ + struct mfd_cell *cell = + info->device->platform_data; + struct tmio_fb_data *data = cell->driver_data; + struct fb_videomode *best = NULL; + int i; + + for (i = 0; i < data->num_modes; i++) { + struct fb_videomode *mode = data->modes + i; + + if (mode->xres >= var->xres && mode->yres >= var->yres + && (!best || (mode->xres < best->xres + && mode->yres < best->yres))) + best = mode; + } + + return best; +} + +static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + + struct fb_videomode *mode; + struct mfd_cell *cell = + info->device->platform_data; + struct tmio_fb_data *data = cell->driver_data; + + mode = tmiofb_find_mode(info, var); + if (!mode || var->bits_per_pixel > 16) + return -EINVAL; + + fb_videomode_to_var(var, mode); + + var->xres_virtual = mode->xres; + var->yres_virtual = info->screen_size / (mode->xres * 2); + + if (var->yres_virtual < var->yres) + return -EINVAL; + + var->xoffset = 0; + var->yoffset = 0; + var->bits_per_pixel = 16; + var->grayscale = 0; + 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 = 0; + var->transp.length = 0; + var->nonstd = 0; + var->height = data->height; /* mm */ + var->width = data->width; /* mm */ + var->rotate = 0; + return 0; +} + +static int tmiofb_set_par(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct fb_videomode *mode; + + mode = tmiofb_find_mode(info, var); + if (!mode) + return -EINVAL; + + info->mode = mode; + info->fix.line_length = info->mode->xres * + var->bits_per_pixel / 8; + + tmiofb_hw_mode(to_platform_device(info->device)); + tmiofb_clearscreen(info); + return 0; +} + +static int tmiofb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct tmiofb_par *par = info->par; + + if (regno < ARRAY_SIZE(par->pseudo_palette)) { + par->pseudo_palette[regno] = + ((red & 0xf800)) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + return 0; + } + + return -EINVAL; +} + +static int tmiofb_blank(int blank, struct fb_info *info) +{ + /* + * everything is done in lcd/bl drivers. + * this is purely to make sysfs happy and work. + */ + return 0; +} + +static struct fb_ops tmiofb_ops = { + .owner = THIS_MODULE, + + .fb_ioctl = tmiofb_ioctl, + .fb_check_var = tmiofb_check_var, + .fb_set_par = tmiofb_set_par, + .fb_setcolreg = tmiofb_setcolreg, + .fb_blank = tmiofb_blank, + .fb_imageblit = cfb_imageblit, +#ifdef CONFIG_FB_TMIO_ACCELL + .fb_sync = tmiofb_sync, + .fb_fillrect = tmiofb_fillrect, + .fb_copyarea = tmiofb_copyarea, +#else + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, +#endif +}; + +/*--------------------------------------------------------------------------*/ + +static int __devinit tmiofb_probe(struct platform_device *dev) +{ + struct mfd_cell *cell = dev->dev.platform_data; + struct tmio_fb_data *data = cell->driver_data; + struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1); + struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0); + struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2); + int irq = platform_get_irq(dev, 0); + struct fb_info *info; + struct tmiofb_par *par; + int retval; + + /* + * This is the only way ATM to disable the fb + */ + if (data == NULL) { + dev_err(&dev->dev, "NULL platform data!\n"); + return -EINVAL; + } + + info = framebuffer_alloc(sizeof(struct tmiofb_par), &dev->dev); + + if (!info) + return -ENOMEM; + + par = info->par; + +#ifdef CONFIG_FB_TMIO_ACCELL + init_waitqueue_head(&par->wait_acc); + + par->use_polling = true; + + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA + | FBINFO_HWACCEL_FILLRECT; +#else + info->flags = FBINFO_DEFAULT; +#endif + + info->fbops = &tmiofb_ops; + + strcpy(info->fix.id, "tmio-fb"); + info->fix.smem_start = vram->start; + info->fix.smem_len = resource_size(vram); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.mmio_start = lcr->start; + info->fix.mmio_len = resource_size(lcr); + info->fix.accel = FB_ACCEL_NONE; + info->screen_size = info->fix.smem_len - (4 * TMIOFB_FIFO_SIZE); + info->pseudo_palette = par->pseudo_palette; + + par->ccr = ioremap(ccr->start, resource_size(ccr)); + if (!par->ccr) { + retval = -ENOMEM; + goto err_ioremap_ccr; + } + + par->lcr = ioremap(info->fix.mmio_start, info->fix.mmio_len); + if (!par->lcr) { + retval = -ENOMEM; + goto err_ioremap_lcr; + } + + info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); + if (!info->screen_base) { + retval = -ENOMEM; + goto err_ioremap_vram; + } + + retval = request_irq(irq, &tmiofb_irq, IRQF_DISABLED, + dev->dev.bus_id, info); + + if (retval) + goto err_request_irq; + + platform_set_drvdata(dev, info); + + retval = fb_find_mode(&info->var, info, mode_option, + data->modes, data->num_modes, + data->modes, 16); + if (!retval) { + retval = -EINVAL; + goto err_find_mode; + } + + if (cell->enable) { + retval = cell->enable(dev); + if (retval) + goto err_enable; + } + + retval = tmiofb_hw_init(dev); + if (retval) + goto err_hw_init; + + fb_videomode_to_modelist(data->modes, data->num_modes, + &info->modelist); + + retval = register_framebuffer(info); + if (retval < 0) + goto err_register_framebuffer; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + + return 0; + +err_register_framebuffer: +/*err_set_par:*/ + tmiofb_hw_stop(dev); +err_hw_init: + if (cell->disable) + cell->disable(dev); +err_enable: +err_find_mode: + platform_set_drvdata(dev, NULL); + free_irq(irq, info); +err_request_irq: + iounmap(info->screen_base); +err_ioremap_vram: + iounmap(par->lcr); +err_ioremap_lcr: + iounmap(par->ccr); +err_ioremap_ccr: + framebuffer_release(info); + return retval; +} + +static int __devexit tmiofb_remove(struct platform_device *dev) +{ + struct mfd_cell *cell = dev->dev.platform_data; + struct fb_info *info = platform_get_drvdata(dev); + int irq = platform_get_irq(dev, 0); + struct tmiofb_par *par; + + if (info) { + par = info->par; + unregister_framebuffer(info); + + tmiofb_hw_stop(dev); + + if (cell->disable) + cell->disable(dev); + + platform_set_drvdata(dev, NULL); + + free_irq(irq, info); + + iounmap(info->screen_base); + iounmap(par->lcr); + iounmap(par->ccr); + + framebuffer_release(info); + } + + return 0; +} + +#ifdef DEBUG +static void tmiofb_dump_regs(struct platform_device *dev) +{ + struct fb_info *info = platform_get_drvdata(dev); + struct tmiofb_par *par = info->par; + + printk(KERN_DEBUG "lhccr:\n"); +#define CCR_PR(n) printk(KERN_DEBUG "\t" #n " = \t%04x\n",\ + tmio_ioread16(par->ccr + CCR_ ## n)); + CCR_PR(CMD); + CCR_PR(REVID); + CCR_PR(BASEL); + CCR_PR(BASEH); + CCR_PR(UGCC); + CCR_PR(GCC); + CCR_PR(USC); + CCR_PR(VRAMRTC); + CCR_PR(VRAMSAC); + CCR_PR(VRAMBC); +#undef CCR_PR + + printk(KERN_DEBUG "lcr: \n"); +#define LCR_PR(n) printk(KERN_DEBUG "\t" #n " = \t%04x\n",\ + tmio_ioread16(par->lcr + LCR_ ## n)); + LCR_PR(UIS); + LCR_PR(VHPN); + LCR_PR(CFSAL); + LCR_PR(CFSAH); + LCR_PR(CFS); + LCR_PR(CFWS); + LCR_PR(BBIE); + LCR_PR(BBISC); + LCR_PR(CCS); + LCR_PR(BBES); + LCR_PR(CMDL); + LCR_PR(CMDH); + LCR_PR(CFC); + LCR_PR(CCIFC); + LCR_PR(HWT); + LCR_PR(LCDCCRC); + LCR_PR(LCDCC); + LCR_PR(LCDCOPC); + LCR_PR(LCDIS); + LCR_PR(LCDIM); + LCR_PR(LCDIE); + LCR_PR(GDSAL); + LCR_PR(GDSAH); + LCR_PR(VHPCL); + LCR_PR(VHPCH); + LCR_PR(GM); + LCR_PR(HT); + LCR_PR(HDS); + LCR_PR(HSS); + LCR_PR(HSE); + LCR_PR(HNP); + LCR_PR(VT); + LCR_PR(VDS); + LCR_PR(VSS); + LCR_PR(VSE); + LCR_PR(CDLN); + LCR_PR(ILN); + LCR_PR(SP); + LCR_PR(MISC); + LCR_PR(VIHSS); + LCR_PR(VIVS); + LCR_PR(VIVE); + LCR_PR(VIVSS); + LCR_PR(VCCIS); + LCR_PR(VIDWSAL); + LCR_PR(VIDWSAH); + LCR_PR(VIDRSAL); + LCR_PR(VIDRSAH); + LCR_PR(VIPDDST); + LCR_PR(VIPDDET); + LCR_PR(VIE); + LCR_PR(VCS); + LCR_PR(VPHWC); + LCR_PR(VPHS); + LCR_PR(VPVWC); + LCR_PR(VPVS); + LCR_PR(PLHPIX); + LCR_PR(XS); + LCR_PR(XCKHW); + LCR_PR(STHS); + LCR_PR(VT2); + LCR_PR(YCKSW); + LCR_PR(YSTS); + LCR_PR(PPOLS); + LCR_PR(PRECW); + LCR_PR(VCLKHW); + LCR_PR(OC); +#undef LCR_PR +} +#endif + +#ifdef CONFIG_PM +static int tmiofb_suspend(struct platform_device *dev, pm_message_t state) +{ + struct fb_info *info = platform_get_drvdata(dev); + struct tmiofb_par *par = info->par; + struct mfd_cell *cell = dev->dev.platform_data; + int retval = 0; + + acquire_console_sem(); + + fb_set_suspend(info, 1); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + + /* + * The fb should be usable even if interrupts are disabled (and they are + * during suspend/resume). Switch temporary to forced polling. + */ + printk(KERN_INFO "tmiofb: switching to polling\n"); + par->use_polling = true; + tmiofb_hw_stop(dev); + + if (cell->suspend) + retval = cell->suspend(dev); + + release_console_sem(); + + return retval; +} + +static int tmiofb_resume(struct platform_device *dev) +{ + struct fb_info *info = platform_get_drvdata(dev); + struct mfd_cell *cell = dev->dev.platform_data; + int retval; + + acquire_console_sem(); + + if (cell->resume) { + retval = cell->resume(dev); + if (retval) + goto out; + } + + tmiofb_irq(-1, info); + + tmiofb_hw_init(dev); + + tmiofb_hw_mode(dev); + + fb_set_suspend(info, 0); +out: + release_console_sem(); + return retval; +} +#else +#define tmiofb_suspend NULL +#define tmiofb_resume NULL +#endif + +static struct platform_driver tmiofb_driver = { + .driver.name = "tmio-fb", + .driver.owner = THIS_MODULE, + .probe = tmiofb_probe, + .remove = __devexit_p(tmiofb_remove), + .suspend = tmiofb_suspend, + .resume = tmiofb_resume, +}; + +/*--------------------------------------------------------------------------*/ + +#ifndef MODULE +static void __init tmiofb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + /* + * FIXME + */ + } +} +#endif + +static int __init tmiofb_init(void) +{ +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("tmiofb", &option)) + return -ENODEV; + tmiofb_setup(option); +#endif + return platform_driver_register(&tmiofb_driver); +} + +static void __exit tmiofb_cleanup(void) +{ + platform_driver_unregister(&tmiofb_driver); +} + +module_init(tmiofb_init); +module_exit(tmiofb_cleanup); + +MODULE_DESCRIPTION("TMIO framebuffer driver"); +MODULE_AUTHOR("Chris Humbert, Dirk Opfer, Dmitry Baryshkov"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 50744229c7a..6c2d37fdd3b 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -516,10 +516,12 @@ static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task, err = uvesafb_exec(task); if (err || (task->t.regs.eax & 0xffff) != 0x004f) { - printk(KERN_ERR "uvesafb: Getting mode info block " + printk(KERN_WARNING "uvesafb: Getting mode info block " "for mode 0x%x failed (eax=0x%x, err=%d)\n", *mode, (u32)task->t.regs.eax, err); - return -EINVAL; + mode++; + par->vbe_modes_cnt--; + continue; } mib = task->buf; @@ -548,7 +550,10 @@ static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task, mib->depth = mib->bits_per_pixel; } - return 0; + if (par->vbe_modes_cnt > 0) + return 0; + else + return -EINVAL; } /* diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index e31bca8a0cb..5b2938903ac 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -58,7 +58,6 @@ struct vga16fb_par { unsigned char ClockingMode; /* Seq-Controller:01h */ } vga_state; struct vgastate state; - struct mutex open_lock; unsigned int ref_count; int palette_blanked, vesa_blanked, mode, isVGA; u8 misc, pel_msk, vss, clkdiv; @@ -286,7 +285,6 @@ static int vga16fb_open(struct fb_info *info, int user) { struct vga16fb_par *par = info->par; - mutex_lock(&par->open_lock); if (!par->ref_count) { memset(&par->state, 0, sizeof(struct vgastate)); par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE | @@ -294,7 +292,6 @@ static int vga16fb_open(struct fb_info *info, int user) save_vga(&par->state); } par->ref_count++; - mutex_unlock(&par->open_lock); return 0; } @@ -303,15 +300,12 @@ static int vga16fb_release(struct fb_info *info, int user) { struct vga16fb_par *par = info->par; - mutex_lock(&par->open_lock); - if (!par->ref_count) { - mutex_unlock(&par->open_lock); + if (!par->ref_count) return -EINVAL; - } + if (par->ref_count == 1) restore_vga(&par->state); par->ref_count--; - mutex_unlock(&par->open_lock); return 0; } @@ -1326,7 +1320,6 @@ static int __init vga16fb_probe(struct platform_device *dev) printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base); par = info->par; - mutex_init(&par->open_lock); par->isVGA = screen_info.orig_video_isVGA; par->palette_blanked = 0; par->vesa_blanked = 0; diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile new file mode 100644 index 00000000000..e533b4b6aba --- /dev/null +++ b/drivers/video/via/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the VIA framebuffer driver (for Linux Kernel 2.6) +# + +obj-$(CONFIG_FB_VIA) += viafb.o + +viafb-y :=viafbdev.o hw.o iface.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c new file mode 100644 index 00000000000..632523ff1fb --- /dev/null +++ b/drivers/video/via/accel.c @@ -0,0 +1,279 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "global.h" + +void viafb_init_accel(void) +{ + viaparinfo->fbmem_free -= CURSOR_SIZE; + viaparinfo->cursor_start = viaparinfo->fbmem_free; + viaparinfo->fbmem_used += CURSOR_SIZE; + + /* Reverse 8*1024 memory space for cursor image */ + viaparinfo->fbmem_free -= (CURSOR_SIZE + VQ_SIZE); + viaparinfo->VQ_start = viaparinfo->fbmem_free; + viaparinfo->VQ_end = viaparinfo->VQ_start + VQ_SIZE - 1; + viaparinfo->fbmem_used += (CURSOR_SIZE + VQ_SIZE); } + +void viafb_init_2d_engine(void) +{ + u32 dwVQStartAddr, dwVQEndAddr; + u32 dwVQLen, dwVQStartL, dwVQEndL, dwVQStartEndH; + + /* init 2D engine regs to reset 2D engine */ + writel(0x0, viaparinfo->io_virt + VIA_REG_GEMODE); + writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS); + writel(0x0, viaparinfo->io_virt + VIA_REG_DSTPOS); + writel(0x0, viaparinfo->io_virt + VIA_REG_DIMENSION); + writel(0x0, viaparinfo->io_virt + VIA_REG_PATADDR); + writel(0x0, viaparinfo->io_virt + VIA_REG_FGCOLOR); + writel(0x0, viaparinfo->io_virt + VIA_REG_BGCOLOR); + writel(0x0, viaparinfo->io_virt + VIA_REG_CLIPTL); + writel(0x0, viaparinfo->io_virt + VIA_REG_CLIPBR); + writel(0x0, viaparinfo->io_virt + VIA_REG_OFFSET); + writel(0x0, viaparinfo->io_virt + VIA_REG_KEYCONTROL); + writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE); + writel(0x0, viaparinfo->io_virt + VIA_REG_DSTBASE); + writel(0x0, viaparinfo->io_virt + VIA_REG_PITCH); + writel(0x0, viaparinfo->io_virt + VIA_REG_MONOPAT1); + + /* Init AGP and VQ regs */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + case UNICHROME_P4M900: + writel(0x00100000, viaparinfo->io_virt + VIA_REG_CR_TRANSET); + writel(0x680A0000, viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + writel(0x02000000, viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + break; + + default: + writel(0x00100000, viaparinfo->io_virt + VIA_REG_TRANSET); + writel(0x00000000, viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x00333004, viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x60000000, viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x61000000, viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x62000000, viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x63000000, viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x64000000, viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x7D000000, viaparinfo->io_virt + VIA_REG_TRANSPACE); + + writel(0xFE020000, viaparinfo->io_virt + VIA_REG_TRANSET); + writel(0x00000000, viaparinfo->io_virt + VIA_REG_TRANSPACE); + break; + } + if (viaparinfo->VQ_start != 0) { + /* Enable VQ */ + dwVQStartAddr = viaparinfo->VQ_start; + dwVQEndAddr = viaparinfo->VQ_end; + + dwVQStartL = 0x50000000 | (dwVQStartAddr & 0xFFFFFF); + dwVQEndL = 0x51000000 | (dwVQEndAddr & 0xFFFFFF); + dwVQStartEndH = 0x52000000 | + ((dwVQStartAddr & 0xFF000000) >> 24) | + ((dwVQEndAddr & 0xFF000000) >> 16); + dwVQLen = 0x53000000 | (VQ_SIZE >> 3); + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + case UNICHROME_P4M900: + dwVQStartL |= 0x20000000; + dwVQEndL |= 0x20000000; + dwVQStartEndH |= 0x20000000; + dwVQLen |= 0x20000000; + break; + default: + break; + } + + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + case UNICHROME_P4M900: + writel(0x00100000, + viaparinfo->io_virt + VIA_REG_CR_TRANSET); + writel(dwVQStartEndH, + viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + writel(dwVQStartL, + viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + writel(dwVQEndL, + viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + writel(dwVQLen, + viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + writel(0x74301001, + viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + writel(0x00000000, + viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + break; + default: + writel(0x00FE0000, + viaparinfo->io_virt + VIA_REG_TRANSET); + writel(0x080003FE, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x0A00027C, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x0B000260, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x0C000274, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x0D000264, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x0E000000, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x0F000020, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x1000027E, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x110002FE, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x200F0060, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + + writel(0x00000006, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x40008C0F, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x44000000, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x45080C04, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x46800408, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + + writel(dwVQStartEndH, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(dwVQStartL, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(dwVQEndL, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(dwVQLen, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + break; + } + } else { + /* Disable VQ */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + case UNICHROME_P4M900: + writel(0x00100000, + viaparinfo->io_virt + VIA_REG_CR_TRANSET); + writel(0x74301000, + viaparinfo->io_virt + VIA_REG_CR_TRANSPACE); + break; + default: + writel(0x00FE0000, + viaparinfo->io_virt + VIA_REG_TRANSET); + writel(0x00000004, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x40008C0F, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x44000000, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x45080C04, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + writel(0x46800408, + viaparinfo->io_virt + VIA_REG_TRANSPACE); + break; + } + } + + viafb_set_2d_color_depth(viaparinfo->bpp); + + writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE); + writel(0x0, viaparinfo->io_virt + VIA_REG_DSTBASE); + + writel(VIA_PITCH_ENABLE | + (((viaparinfo->hres * + viaparinfo->bpp >> 3) >> 3) | (((viaparinfo->hres * + viaparinfo-> + bpp >> 3) >> 3) << 16)), + viaparinfo->io_virt + VIA_REG_PITCH); +} + +void viafb_set_2d_color_depth(int bpp) +{ + u32 dwGEMode; + + dwGEMode = readl(viaparinfo->io_virt + 0x04) & 0xFFFFFCFF; + + switch (bpp) { + case 16: + dwGEMode |= VIA_GEM_16bpp; + break; + case 32: + dwGEMode |= VIA_GEM_32bpp; + break; + default: + dwGEMode |= VIA_GEM_8bpp; + break; + } + + /* Set BPP and Pitch */ + writel(dwGEMode, viaparinfo->io_virt + VIA_REG_GEMODE); +} + +void viafb_hw_cursor_init(void) +{ + /* Set Cursor Image Base Address */ + writel(viaparinfo->cursor_start, + viaparinfo->io_virt + VIA_REG_CURSOR_MODE); + writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_POS); + writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_ORG); + writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_BG); + writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_FG); +} + +void viafb_show_hw_cursor(struct fb_info *info, int Status) +{ + u32 temp; + u32 iga_path = ((struct viafb_par *)(info->par))->iga_path; + + temp = readl(viaparinfo->io_virt + VIA_REG_CURSOR_MODE); + switch (Status) { + case HW_Cursor_ON: + temp |= 0x1; + break; + case HW_Cursor_OFF: + temp &= 0xFFFFFFFE; + break; + } + switch (iga_path) { + case IGA2: + temp |= 0x80000000; + break; + case IGA1: + default: + temp &= 0x7FFFFFFF; + } + writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_MODE); +} + +int viafb_wait_engine_idle(void) +{ + int loop = 0; + + while (!(readl(viaparinfo->io_virt + VIA_REG_STATUS) & + VIA_VR_QUEUE_BUSY) && (loop++ < MAXLOOP)) + cpu_relax(); + + while ((readl(viaparinfo->io_virt + VIA_REG_STATUS) & + (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) && + (loop++ < MAXLOOP)) + cpu_relax(); + + return loop >= MAXLOOP; +} diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h new file mode 100644 index 00000000000..29bf854e8cc --- /dev/null +++ b/drivers/video/via/accel.h @@ -0,0 +1,169 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ACCEL_H__ +#define __ACCEL_H__ + +#define FB_ACCEL_VIA_UNICHROME 50 + +/* MMIO Base Address Definition */ +#define MMIO_VGABASE 0x8000 +#define MMIO_CR_READ (MMIO_VGABASE + 0x3D4) +#define MMIO_CR_WRITE (MMIO_VGABASE + 0x3D5) +#define MMIO_SR_READ (MMIO_VGABASE + 0x3C4) +#define MMIO_SR_WRITE (MMIO_VGABASE + 0x3C5) + +/* HW Cursor Status Define */ +#define HW_Cursor_ON 0 +#define HW_Cursor_OFF 1 + +#define CURSOR_SIZE (8 * 1024) +#define VQ_SIZE (256 * 1024) + +#define VIA_MMIO_BLTBASE 0x200000 +#define VIA_MMIO_BLTSIZE 0x200000 + +/* Defines for 2D registers */ +#define VIA_REG_GECMD 0x000 +#define VIA_REG_GEMODE 0x004 +#define VIA_REG_SRCPOS 0x008 +#define VIA_REG_DSTPOS 0x00C +/* width and height */ +#define VIA_REG_DIMENSION 0x010 +#define VIA_REG_PATADDR 0x014 +#define VIA_REG_FGCOLOR 0x018 +#define VIA_REG_BGCOLOR 0x01C +/* top and left of clipping */ +#define VIA_REG_CLIPTL 0x020 +/* bottom and right of clipping */ +#define VIA_REG_CLIPBR 0x024 +#define VIA_REG_OFFSET 0x028 +/* color key control */ +#define VIA_REG_KEYCONTROL 0x02C +#define VIA_REG_SRCBASE 0x030 +#define VIA_REG_DSTBASE 0x034 +/* pitch of src and dst */ +#define VIA_REG_PITCH 0x038 +#define VIA_REG_MONOPAT0 0x03C +#define VIA_REG_MONOPAT1 0x040 +/* from 0x100 to 0x1ff */ +#define VIA_REG_COLORPAT 0x100 + +/* VIA_REG_PITCH(0x38): Pitch Setting */ +#define VIA_PITCH_ENABLE 0x80000000 + +/* defines for VIA HW cursor registers */ +#define VIA_REG_CURSOR_MODE 0x2D0 +#define VIA_REG_CURSOR_POS 0x2D4 +#define VIA_REG_CURSOR_ORG 0x2D8 +#define VIA_REG_CURSOR_BG 0x2DC +#define VIA_REG_CURSOR_FG 0x2E0 + +/* VIA_REG_GEMODE(0x04): GE mode */ +#define VIA_GEM_8bpp 0x00000000 +#define VIA_GEM_16bpp 0x00000100 +#define VIA_GEM_32bpp 0x00000300 + +/* VIA_REG_GECMD(0x00): 2D Engine Command */ +#define VIA_GEC_NOOP 0x00000000 +#define VIA_GEC_BLT 0x00000001 +#define VIA_GEC_LINE 0x00000005 + +/* Rotate Command */ +#define VIA_GEC_ROT 0x00000008 + +#define VIA_GEC_SRC_XY 0x00000000 +#define VIA_GEC_SRC_LINEAR 0x00000010 +#define VIA_GEC_DST_XY 0x00000000 +#define VIA_GEC_DST_LINRAT 0x00000020 + +#define VIA_GEC_SRC_FB 0x00000000 +#define VIA_GEC_SRC_SYS 0x00000040 +#define VIA_GEC_DST_FB 0x00000000 +#define VIA_GEC_DST_SYS 0x00000080 + +/* source is mono */ +#define VIA_GEC_SRC_MONO 0x00000100 +/* pattern is mono */ +#define VIA_GEC_PAT_MONO 0x00000200 +/* mono src is opaque */ +#define VIA_GEC_MSRC_OPAQUE 0x00000000 +/* mono src is transparent */ +#define VIA_GEC_MSRC_TRANS 0x00000400 +/* pattern is in frame buffer */ +#define VIA_GEC_PAT_FB 0x00000000 +/* pattern is from reg setting */ +#define VIA_GEC_PAT_REG 0x00000800 + +#define VIA_GEC_CLIP_DISABLE 0x00000000 +#define VIA_GEC_CLIP_ENABLE 0x00001000 + +#define VIA_GEC_FIXCOLOR_PAT 0x00002000 + +#define VIA_GEC_INCX 0x00000000 +#define VIA_GEC_DECY 0x00004000 +#define VIA_GEC_INCY 0x00000000 +#define VIA_GEC_DECX 0x00008000 +/* mono pattern is opaque */ +#define VIA_GEC_MPAT_OPAQUE 0x00000000 +/* mono pattern is transparent */ +#define VIA_GEC_MPAT_TRANS 0x00010000 + +#define VIA_GEC_MONO_UNPACK 0x00000000 +#define VIA_GEC_MONO_PACK 0x00020000 +#define VIA_GEC_MONO_DWORD 0x00000000 +#define VIA_GEC_MONO_WORD 0x00040000 +#define VIA_GEC_MONO_BYTE 0x00080000 + +#define VIA_GEC_LASTPIXEL_ON 0x00000000 +#define VIA_GEC_LASTPIXEL_OFF 0x00100000 +#define VIA_GEC_X_MAJOR 0x00000000 +#define VIA_GEC_Y_MAJOR 0x00200000 +#define VIA_GEC_QUICK_START 0x00800000 + +/* defines for VIA 3D registers */ +#define VIA_REG_STATUS 0x400 +#define VIA_REG_CR_TRANSET 0x41C +#define VIA_REG_CR_TRANSPACE 0x420 +#define VIA_REG_TRANSET 0x43C +#define VIA_REG_TRANSPACE 0x440 + +/* VIA_REG_STATUS(0x400): Engine Status */ + +/* Command Regulator is busy */ +#define VIA_CMD_RGTR_BUSY 0x00000080 +/* 2D Engine is busy */ +#define VIA_2D_ENG_BUSY 0x00000002 +/* 3D Engine is busy */ +#define VIA_3D_ENG_BUSY 0x00000001 +/* Virtual Queue is busy */ +#define VIA_VR_QUEUE_BUSY 0x00020000 + +#define MAXLOOP 0xFFFFFF + +void viafb_init_accel(void); +void viafb_init_2d_engine(void); +void set_2d_color_depth(int); +void viafb_hw_cursor_init(void); +void viafb_show_hw_cursor(struct fb_info *info, int Status); int +viafb_wait_engine_idle(void); void viafb_set_2d_color_depth(int bpp); + +#endif /* __ACCEL_H__ */ diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h new file mode 100644 index 00000000000..dde95edc387 --- /dev/null +++ b/drivers/video/via/chip.h @@ -0,0 +1,190 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __CHIP_H__ +#define __CHIP_H__ + +#include "global.h" + +/***************************************/ +/* Definition Graphic Chip Information */ +/***************************************/ + +#define PCI_VIA_VENDOR_ID 0x1106 + +/* Define VIA Graphic Chip Name */ +#define UNICHROME_CLE266 1 +#define UNICHROME_CLE266_DID 0x3122 +#define CLE266_REVISION_AX 0x0A +#define CLE266_REVISION_CX 0x0C + +#define UNICHROME_K400 2 +#define UNICHROME_K400_DID 0x7205 + +#define UNICHROME_K800 3 +#define UNICHROME_K800_DID 0x3108 + +#define UNICHROME_PM800 4 +#define UNICHROME_PM800_DID 0x3118 + +#define UNICHROME_CN700 5 +#define UNICHROME_CN700_DID 0x3344 + +#define UNICHROME_CX700 6 +#define UNICHROME_CX700_DID 0x3157 +#define CX700_REVISION_700 0x0 +#define CX700_REVISION_700M 0x1 +#define CX700_REVISION_700M2 0x2 + +#define UNICHROME_CN750 7 +#define UNICHROME_CN750_DID 0x3225 + +#define UNICHROME_K8M890 8 +#define UNICHROME_K8M890_DID 0x3230 + +#define UNICHROME_P4M890 9 +#define UNICHROME_P4M890_DID 0x3343 + +#define UNICHROME_P4M900 10 +#define UNICHROME_P4M900_DID 0x3371 + +#define UNICHROME_VX800 11 +#define UNICHROME_VX800_DID 0x1122 + +/**************************************************/ +/* Definition TMDS Trasmitter Information */ +/**************************************************/ + +/* Definition TMDS Trasmitter Index */ +#define NON_TMDS_TRANSMITTER 0x00 +#define VT1632_TMDS 0x01 +#define INTEGRATED_TMDS 0x42 + +/* Definition TMDS Trasmitter I2C Slave Address */ +#define VT1632_TMDS_I2C_ADDR 0x10 + +/**************************************************/ +/* Definition LVDS Trasmitter Information */ +/**************************************************/ + +/* Definition LVDS Trasmitter Index */ +#define NON_LVDS_TRANSMITTER 0x00 +#define VT1631_LVDS 0x01 +#define VT1636_LVDS 0x0E +#define INTEGRATED_LVDS 0x41 + +/* Definition Digital Transmitter Mode */ +#define TX_DATA_12_BITS 0x01 +#define TX_DATA_24_BITS 0x02 +#define TX_DATA_DDR_MODE 0x04 +#define TX_DATA_SDR_MODE 0x08 + +/* Definition LVDS Trasmitter I2C Slave Address */ +#define VT1631_LVDS_I2C_ADDR 0x70 +#define VT3271_LVDS_I2C_ADDR 0x80 +#define VT1636_LVDS_I2C_ADDR 0x80 + +struct tmds_chip_information { + int tmds_chip_name; + int tmds_chip_slave_addr; + int dvi_panel_id; + int data_mode; + int output_interface; + int i2c_port; + int device_type; +}; + +struct lvds_chip_information { + int lvds_chip_name; + int lvds_chip_slave_addr; + int data_mode; + int output_interface; + int i2c_port; +}; + +struct chip_information { + int gfx_chip_name; + int gfx_chip_revision; + int chip_on_slot; + struct tmds_chip_information tmds_chip_info; + struct lvds_chip_information lvds_chip_info; + struct lvds_chip_information lvds_chip_info2; +}; + +struct crt_setting_information { + int iga_path; + int h_active; + int v_active; + int bpp; + int refresh_rate; +}; + +struct tmds_setting_information { + int iga_path; + int h_active; + int v_active; + int bpp; + int refresh_rate; + int get_dvi_size_method; + int max_pixel_clock; + int dvi_panel_size; + int dvi_panel_hres; + int dvi_panel_vres; + int native_size; +}; + +struct lvds_setting_information { + int iga_path; + int h_active; + int v_active; + int bpp; + int refresh_rate; + int get_lcd_size_method; + int lcd_panel_id; + int lcd_panel_size; + int lcd_panel_hres; + int lcd_panel_vres; + int display_method; + int device_lcd_dualedge; + int LCDDithering; + int lcd_mode; + u32 vclk; /*panel mode clock value */ +}; + +struct GFX_DPA_SETTING { + int ClkRangeIndex; + u8 DVP0; /* CR96[3:0] */ + u8 DVP0DataDri_S1; /* SR2A[5] */ + u8 DVP0DataDri_S; /* SR1B[1] */ + u8 DVP0ClockDri_S1; /* SR2A[4] */ + u8 DVP0ClockDri_S; /* SR1E[2] */ + u8 DVP1; /* CR9B[3:0] */ + u8 DVP1Driving; /* SR65[3:0], Data and Clock driving */ + u8 DFPHigh; /* CR97[3:0] */ + u8 DFPLow; /* CR99[3:0] */ + +}; + +struct VT1636_DPA_SETTING { + int PanelSizeID; + u8 CLK_SEL_ST1; + u8 CLK_SEL_ST2; +}; +#endif /* __CHIP_H__ */ diff --git a/drivers/video/via/debug.h b/drivers/video/via/debug.h new file mode 100644 index 00000000000..86eacc2017f --- /dev/null +++ b/drivers/video/via/debug.h @@ -0,0 +1,41 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#ifndef VIAFB_DEBUG +#define VIAFB_DEBUG 0 +#endif + +#if VIAFB_DEBUG +#define DEBUG_MSG(f, a...) printk(f, ## a) +#else +#define DEBUG_MSG(f, a...) +#endif + +#define VIAFB_WARN 0 +#if VIAFB_WARN +#define WARN_MSG(f, a...) printk(f, ## a) +#else +#define WARN_MSG(f, a...) +#endif + +#endif /* __DEBUG_H__ */ diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c new file mode 100644 index 00000000000..d6965447ca6 --- /dev/null +++ b/drivers/video/via/dvi.c @@ -0,0 +1,682 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "global.h" + +static void tmds_register_write(int index, u8 data); +static int tmds_register_read(int index); +static int tmds_register_read_bytes(int index, u8 *buff, int buff_len); +static int check_reduce_blanking_mode(int mode_index, + int refresh_rate); +static int dvi_get_panel_size_from_DDCv1(void); +static int dvi_get_panel_size_from_DDCv2(void); +static unsigned char dvi_get_panel_info(void); +static int viafb_dvi_query_EDID(void); + +static int check_tmds_chip(int device_id_subaddr, int device_id) +{ + if (tmds_register_read(device_id_subaddr) == device_id) + return OK; + else + return FAIL; +} + +void viafb_init_dvi_size(void) +{ + DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n"); + DEBUG_MSG(KERN_INFO + "viaparinfo->tmds_setting_info->get_dvi_size_method %d\n", + viaparinfo->tmds_setting_info->get_dvi_size_method); + + switch (viaparinfo->tmds_setting_info->get_dvi_size_method) { + case GET_DVI_SIZE_BY_SYSTEM_BIOS: + break; + case GET_DVI_SZIE_BY_HW_STRAPPING: + break; + case GET_DVI_SIZE_BY_VGA_BIOS: + default: + dvi_get_panel_info(); + break; + } + return; +} + +int viafb_tmds_trasmitter_identify(void) +{ + unsigned char sr2a = 0, sr1e = 0, sr3e = 0; + + /* Turn on ouputting pad */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + /*=* DFP Low Pad on *=*/ + sr2a = viafb_read_reg(VIASR, SR2A); + viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1); + break; + + case UNICHROME_P4M900: + case UNICHROME_P4M890: + /* DFP Low Pad on */ + sr2a = viafb_read_reg(VIASR, SR2A); + viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1); + /* DVP0 Pad on */ + sr1e = viafb_read_reg(VIASR, SR1E); + viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT6 + BIT7); + break; + + default: + /* DVP0/DVP1 Pad on */ + sr1e = viafb_read_reg(VIASR, SR1E); + viafb_write_reg_mask(SR1E, VIASR, 0xF0, BIT4 + + BIT5 + BIT6 + BIT7); + /* SR3E[1]Multi-function selection: + 0 = Emulate I2C and DDC bus by GPIO2/3/4. */ + sr3e = viafb_read_reg(VIASR, SR3E); + viafb_write_reg_mask(SR3E, VIASR, 0x0, BIT5); + break; + } + + /* Check for VT1632: */ + viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS; + viaparinfo->chip_info-> + tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR; + viaparinfo->chip_info->tmds_chip_info.i2c_port = I2CPORTINDEX; + if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) { + /* + * Currently only support 12bits,dual edge,add 24bits mode later + */ + tmds_register_write(0x08, 0x3b); + + DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n"); + DEBUG_MSG(KERN_INFO "\n %2d", + viaparinfo->chip_info->tmds_chip_info.tmds_chip_name); + DEBUG_MSG(KERN_INFO "\n %2d", + viaparinfo->chip_info->tmds_chip_info.i2c_port); + return OK; + } else { + viaparinfo->chip_info->tmds_chip_info.i2c_port = GPIOPORTINDEX; + if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) + != FAIL) { + tmds_register_write(0x08, 0x3b); + DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n"); + DEBUG_MSG(KERN_INFO "\n %2d", + viaparinfo->chip_info-> + tmds_chip_info.tmds_chip_name); + DEBUG_MSG(KERN_INFO "\n %2d", + viaparinfo->chip_info-> + tmds_chip_info.i2c_port); + return OK; + } + } + + viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = INTEGRATED_TMDS; + + if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) && + ((viafb_display_hardware_layout == HW_LAYOUT_DVI_ONLY) || + (viafb_display_hardware_layout == HW_LAYOUT_LCD_DVI))) { + DEBUG_MSG(KERN_INFO "\n Integrated TMDS ! \n"); + return OK; + } + + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + viafb_write_reg(SR2A, VIASR, sr2a); + break; + + case UNICHROME_P4M900: + case UNICHROME_P4M890: + viafb_write_reg(SR2A, VIASR, sr2a); + viafb_write_reg(SR1E, VIASR, sr1e); + break; + + default: + viafb_write_reg(SR1E, VIASR, sr1e); + viafb_write_reg(SR3E, VIASR, sr3e); + break; + } + + viaparinfo->chip_info-> + tmds_chip_info.tmds_chip_name = NON_TMDS_TRANSMITTER; + viaparinfo->chip_info->tmds_chip_info. + tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR; + return FAIL; +} + +static void tmds_register_write(int index, u8 data) +{ + viaparinfo->i2c_stuff.i2c_port = + viaparinfo->chip_info->tmds_chip_info.i2c_port; + + viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info. + tmds_chip_slave_addr, index, + data); +} + +static int tmds_register_read(int index) +{ + u8 data; + + viaparinfo->i2c_stuff.i2c_port = + viaparinfo->chip_info->tmds_chip_info.i2c_port; + viafb_i2c_readbyte((u8) viaparinfo->chip_info-> + tmds_chip_info.tmds_chip_slave_addr, + (u8) index, &data); + return data; +} + +static int tmds_register_read_bytes(int index, u8 *buff, int buff_len) +{ + viaparinfo->i2c_stuff.i2c_port = + viaparinfo->chip_info->tmds_chip_info.i2c_port; + viafb_i2c_readbytes((u8) viaparinfo->chip_info->tmds_chip_info. + tmds_chip_slave_addr, (u8) index, buff, buff_len); + return 0; +} + +static int check_reduce_blanking_mode(int mode_index, + int refresh_rate) +{ + if (refresh_rate != 60) + return false; + + switch (mode_index) { + /* Following modes have reduce blanking mode. */ + case VIA_RES_1360X768: + case VIA_RES_1400X1050: + case VIA_RES_1440X900: + case VIA_RES_1600X900: + case VIA_RES_1680X1050: + case VIA_RES_1920X1080: + case VIA_RES_1920X1200: + break; + + default: + DEBUG_MSG(KERN_INFO + "This dvi mode %d have no reduce blanking mode!\n", + mode_index); + return false; + } + + return true; +} + +/* DVI Set Mode */ +void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga) +{ + struct VideoModeTable *videoMode = NULL; + struct crt_mode_table *pDviTiming; + unsigned long desirePixelClock, maxPixelClock; + int status = 0; + videoMode = viafb_get_modetbl_pointer(video_index); + pDviTiming = videoMode->crtc; + desirePixelClock = pDviTiming->clk / 1000000; + maxPixelClock = (unsigned long)viaparinfo-> + tmds_setting_info->max_pixel_clock; + + DEBUG_MSG(KERN_INFO "\nDVI_set_mode!!\n"); + + if ((maxPixelClock != 0) && (desirePixelClock > maxPixelClock)) { + /*Check if reduce-blanking mode is exist */ + status = + check_reduce_blanking_mode(video_index, + pDviTiming->refresh_rate); + if (status) { + video_index += 100; /*Use reduce-blanking mode */ + videoMode = viafb_get_modetbl_pointer(video_index); + pDviTiming = videoMode->crtc; + DEBUG_MSG(KERN_INFO + "DVI use reduce blanking mode %d!!\n", + video_index); + } + } + viafb_fill_crtc_timing(pDviTiming, video_index, mode_bpp / 8, set_iga); + viafb_set_output_path(DEVICE_DVI, set_iga, + viaparinfo->chip_info->tmds_chip_info.output_interface); +} + +/* Sense DVI Connector */ +int viafb_dvi_sense(void) +{ + u8 RegSR1E = 0, RegSR3E = 0, RegCR6B = 0, RegCR91 = 0, + RegCR93 = 0, RegCR9B = 0, data; + int ret = false; + + DEBUG_MSG(KERN_INFO "viafb_dvi_sense!!\n"); + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { + /* DI1 Pad on */ + RegSR1E = viafb_read_reg(VIASR, SR1E); + viafb_write_reg(SR1E, VIASR, RegSR1E | 0x30); + + /* CR6B[0]VCK Input Selection: 1 = External clock. */ + RegCR6B = viafb_read_reg(VIACR, CR6B); + viafb_write_reg(CR6B, VIACR, RegCR6B | 0x08); + + /* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off + [0] Software Control Power Sequence */ + RegCR91 = viafb_read_reg(VIACR, CR91); + viafb_write_reg(CR91, VIACR, 0x1D); + + /* CR93[7] DI1 Data Source Selection: 1 = DSP2. + CR93[5] DI1 Clock Source: 1 = internal. + CR93[4] DI1 Clock Polarity. + CR93[3:1] DI1 Clock Adjust. CR93[0] DI1 enable */ + RegCR93 = viafb_read_reg(VIACR, CR93); + viafb_write_reg(CR93, VIACR, 0x01); + } else { + /* DVP0/DVP1 Pad on */ + RegSR1E = viafb_read_reg(VIASR, SR1E); + viafb_write_reg(SR1E, VIASR, RegSR1E | 0xF0); + + /* SR3E[1]Multi-function selection: + 0 = Emulate I2C and DDC bus by GPIO2/3/4. */ + RegSR3E = viafb_read_reg(VIASR, SR3E); + viafb_write_reg(SR3E, VIASR, RegSR3E & (~0x20)); + + /* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off + [0] Software Control Power Sequence */ + RegCR91 = viafb_read_reg(VIACR, CR91); + viafb_write_reg(CR91, VIACR, 0x1D); + + /*CR9B[4] DVP1 Data Source Selection: 1 = From secondary + display.CR9B[2:0] DVP1 Clock Adjust */ + RegCR9B = viafb_read_reg(VIACR, CR9B); + viafb_write_reg(CR9B, VIACR, 0x01); + } + + data = (u8) tmds_register_read(0x09); + if (data & 0x04) + ret = true; + + if (ret == false) { + if (viafb_dvi_query_EDID()) + ret = true; + } + + /* Restore status */ + viafb_write_reg(SR1E, VIASR, RegSR1E); + viafb_write_reg(CR91, VIACR, RegCR91); + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { + viafb_write_reg(CR6B, VIACR, RegCR6B); + viafb_write_reg(CR93, VIACR, RegCR93); + } else { + viafb_write_reg(SR3E, VIASR, RegSR3E); + viafb_write_reg(CR9B, VIACR, RegCR9B); + } + + return ret; +} + +/* Query Flat Panel's EDID Table Version Through DVI Connector */ +static int viafb_dvi_query_EDID(void) +{ + u8 data0, data1; + int restore; + + DEBUG_MSG(KERN_INFO "viafb_dvi_query_EDID!!\n"); + + restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr; + viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0; + + data0 = (u8) tmds_register_read(0x00); + data1 = (u8) tmds_register_read(0x01); + if ((data0 == 0) && (data1 == 0xFF)) { + viaparinfo->chip_info-> + tmds_chip_info.tmds_chip_slave_addr = restore; + return EDID_VERSION_1; /* Found EDID1 Table */ + } + + data0 = (u8) tmds_register_read(0x00); + viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore; + if (data0 == 0x20) + return EDID_VERSION_2; /* Found EDID2 Table */ + else + return false; +} + +/* + * + * int dvi_get_panel_size_from_DDCv1(void) + * + * - Get Panel Size Using EDID1 Table + * + * Return Type: int + * + */ +static int dvi_get_panel_size_from_DDCv1(void) +{ + int i, max_h = 0, max_v = 0, tmp, restore; + unsigned char rData; + unsigned char EDID_DATA[18]; + + DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv1 \n"); + + restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr; + viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0; + + rData = tmds_register_read(0x23); + if (rData & 0x3C) + max_h = 640; + if (rData & 0xC0) + max_h = 720; + if (rData & 0x03) + max_h = 800; + + rData = tmds_register_read(0x24); + if (rData & 0xC0) + max_h = 800; + if (rData & 0x1E) + max_h = 1024; + if (rData & 0x01) + max_h = 1280; + + for (i = 0x25; i < 0x6D; i++) { + switch (i) { + case 0x26: + case 0x28: + case 0x2A: + case 0x2C: + case 0x2E: + case 0x30: + case 0x32: + case 0x34: + rData = tmds_register_read(i); + if (rData == 1) + break; + /* data = (data + 31) * 8 */ + tmp = (rData + 31) << 3; + if (tmp > max_h) + max_h = tmp; + break; + + case 0x36: + case 0x48: + case 0x5A: + case 0x6C: + tmds_register_read_bytes(i, EDID_DATA, 10); + if (!(EDID_DATA[0] || EDID_DATA[1])) { + /* The first two byte must be zero. */ + if (EDID_DATA[3] == 0xFD) { + /* To get max pixel clock. */ + viaparinfo->tmds_setting_info-> + max_pixel_clock = EDID_DATA[9] * 10; + } + } + break; + + default: + break; + } + } + + switch (max_h) { + case 640: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_640X480; + break; + case 800: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_800X600; + break; + case 1024: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1024X768; + break; + case 1280: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1280X1024; + break; + case 1400: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1400X1050; + break; + case 1440: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1440X1050; + break; + case 1600: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1600X1200; + break; + case 1920: + if (max_v == 1200) { + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1920X1200; + } else { + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1920X1080; + } + + break; + default: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1024X768; + DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d !\ + set default panel size.\n", max_h); + break; + } + + DEBUG_MSG(KERN_INFO "DVI max pixelclock = %d\n", + viaparinfo->tmds_setting_info->max_pixel_clock); + viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore; + return viaparinfo->tmds_setting_info->dvi_panel_size; +} + +/* + * + * int dvi_get_panel_size_from_DDCv2(void) + * + * - Get Panel Size Using EDID2 Table + * + * Return Type: int + * + */ +static int dvi_get_panel_size_from_DDCv2(void) +{ + int HSize = 0, restore; + unsigned char R_Buffer[2]; + + DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv2 \n"); + + restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr; + viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA2; + + /* Horizontal: 0x76, 0x77 */ + tmds_register_read_bytes(0x76, R_Buffer, 2); + HSize = R_Buffer[0]; + HSize += R_Buffer[1] << 8; + + switch (HSize) { + case 640: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_640X480; + break; + case 800: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_800X600; + break; + case 1024: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1024X768; + break; + case 1280: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1280X1024; + break; + case 1400: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1400X1050; + break; + case 1440: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1440X1050; + break; + case 1600: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1600X1200; + break; + default: + viaparinfo->tmds_setting_info->dvi_panel_size = + VIA_RES_1024X768; + DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d!\ + set default panel size.\n", HSize); + break; + } + + viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore; + return viaparinfo->tmds_setting_info->dvi_panel_size; +} + +/* + * + * unsigned char dvi_get_panel_info(void) + * + * - Get Panel Size + * + * Return Type: unsigned char + */ +static unsigned char dvi_get_panel_info(void) +{ + unsigned char dvipanelsize; + DEBUG_MSG(KERN_INFO "dvi_get_panel_info! \n"); + + viafb_dvi_sense(); + switch (viafb_dvi_query_EDID()) { + case 1: + dvi_get_panel_size_from_DDCv1(); + break; + case 2: + dvi_get_panel_size_from_DDCv2(); + break; + default: + break; + } + + DEBUG_MSG(KERN_INFO "dvi panel size is %2d \n", + viaparinfo->tmds_setting_info->dvi_panel_size); + dvipanelsize = (unsigned char)(viaparinfo-> + tmds_setting_info->dvi_panel_size); + return dvipanelsize; +} + +/* If Disable DVI, turn off pad */ +void viafb_dvi_disable(void) +{ + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_DVP0) + viafb_write_reg(SR1E, VIASR, + viafb_read_reg(VIASR, SR1E) & (~0xC0)); + + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_DVP1) + viafb_write_reg(SR1E, VIASR, + viafb_read_reg(VIASR, SR1E) & (~0x30)); + + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_DFP_HIGH) + viafb_write_reg(SR2A, VIASR, + viafb_read_reg(VIASR, SR2A) & (~0x0C)); + + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_DFP_LOW) + viafb_write_reg(SR2A, VIASR, + viafb_read_reg(VIASR, SR2A) & (~0x03)); + + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_TMDS) + /* Turn off TMDS power. */ + viafb_write_reg(CRD2, VIACR, + viafb_read_reg(VIACR, CRD2) | 0x08); +} + +/* If Enable DVI, turn off pad */ +void viafb_dvi_enable(void) +{ + u8 data; + + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_DVP0) { + viafb_write_reg(SR1E, VIASR, + viafb_read_reg(VIASR, SR1E) | 0xC0); + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + tmds_register_write(0x88, 0x3b); + else + /*clear CR91[5] to direct on display period + in the secondary diplay path */ + viafb_write_reg(CR91, VIACR, + viafb_read_reg(VIACR, CR91) & 0xDF); + } + + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_DVP1) { + viafb_write_reg(SR1E, VIASR, + viafb_read_reg(VIASR, SR1E) | 0x30); + + /*fix dvi cann't be enabled with MB VT5718C4 - Al Zhang */ + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { + tmds_register_write(0x88, 0x3b); + } else { + /*clear CR91[5] to direct on display period + in the secondary diplay path */ + viafb_write_reg(CR91, VIACR, + viafb_read_reg(VIACR, CR91) & 0xDF); + } + + /*fix DVI cannot enable on EPIA-M board */ + if (viafb_platform_epia_dvi == 1) { + viafb_write_reg_mask(CR91, VIACR, 0x1f, 0x1f); + viafb_write_reg_mask(CR88, VIACR, 0x00, BIT6 + BIT0); + if (viafb_bus_width == 24) { + if (viafb_device_lcd_dualedge == 1) + data = 0x3F; + else + data = 0x37; + viafb_i2c_writebyte(viaparinfo->chip_info-> + tmds_chip_info. + tmds_chip_slave_addr, + 0x08, data); + } + } + } + + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_DFP_HIGH) { + viafb_write_reg(SR2A, VIASR, + viafb_read_reg(VIASR, SR2A) | 0x0C); + viafb_write_reg(CR91, VIACR, + viafb_read_reg(VIACR, CR91) & 0xDF); + } + + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_DFP_LOW) { + viafb_write_reg(SR2A, VIASR, + viafb_read_reg(VIASR, SR2A) | 0x03); + viafb_write_reg(CR91, VIACR, + viafb_read_reg(VIACR, CR91) & 0xDF); + } + if (viaparinfo->chip_info-> + tmds_chip_info.output_interface == INTERFACE_TMDS) { + /* Turn on Display period in the panel path. */ + viafb_write_reg_mask(CR91, VIACR, 0, BIT7); + + /* Turn on TMDS power. */ + viafb_write_reg_mask(CRD2, VIACR, 0, BIT3); + } +} + diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h new file mode 100644 index 00000000000..e1ec37fb0dc --- /dev/null +++ b/drivers/video/via/dvi.h @@ -0,0 +1,64 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DVI_H__ +#define __DVI_H__ + +/*Definition TMDS Device ID register*/ +#define VT1632_DEVICE_ID_REG 0x02 +#define VT1632_DEVICE_ID 0x92 + +#define GET_DVI_SIZE_BY_SYSTEM_BIOS 0x01 +#define GET_DVI_SIZE_BY_VGA_BIOS 0x02 +#define GET_DVI_SZIE_BY_HW_STRAPPING 0x03 + +/* Definition DVI Panel ID*/ +/* Resolution: 640x480, Channel: single, Dithering: Enable */ +#define DVI_PANEL_ID0_640X480 0x00 +/* Resolution: 800x600, Channel: single, Dithering: Enable */ +#define DVI_PANEL_ID1_800x600 0x01 +/* Resolution: 1024x768, Channel: single, Dithering: Enable */ +#define DVI_PANEL_ID1_1024x768 0x02 +/* Resolution: 1280x768, Channel: single, Dithering: Enable */ +#define DVI_PANEL_ID1_1280x768 0x03 +/* Resolution: 1280x1024, Channel: dual, Dithering: Enable */ +#define DVI_PANEL_ID1_1280x1024 0x04 +/* Resolution: 1400x1050, Channel: dual, Dithering: Enable */ +#define DVI_PANEL_ID1_1400x1050 0x05 +/* Resolution: 1600x1200, Channel: dual, Dithering: Enable */ +#define DVI_PANEL_ID1_1600x1200 0x06 + +/* Define the version of EDID*/ +#define EDID_VERSION_1 1 +#define EDID_VERSION_2 2 + +#define DEV_CONNECT_DVI 0x01 +#define DEV_CONNECT_HDMI 0x02 + +struct VideoModeTable *viafb_get_cea_mode_tbl_pointer(int Index); +int viafb_dvi_sense(void); +void viafb_dvi_disable(void); +void viafb_dvi_enable(void); +int viafb_tmds_trasmitter_identify(void); +void viafb_init_dvi_size(void); +void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga); + +#endif /* __DVI_H__ */ diff --git a/drivers/video/via/global.c b/drivers/video/via/global.c new file mode 100644 index 00000000000..468be2425af --- /dev/null +++ b/drivers/video/via/global.c @@ -0,0 +1,60 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include "global.h" +int viafb_platform_epia_dvi = STATE_OFF; +int viafb_device_lcd_dualedge = STATE_OFF; +int viafb_bus_width = 12; +int viafb_display_hardware_layout = HW_LAYOUT_LCD_DVI; +int viafb_memsize; +int viafb_DeviceStatus = CRT_Device; +int viafb_hotplug; +int viafb_refresh = 60; +int viafb_refresh1 = 60; +int viafb_lcd_dsp_method = LCD_EXPANDSION; +int viafb_lcd_mode = LCD_OPENLDI; +int viafb_bpp = 32; +int viafb_bpp1 = 32; +int viafb_accel = 1; +int viafb_CRT_ON = 1; +int viafb_DVI_ON; +int viafb_LCD_ON ; +int viafb_LCD2_ON; +int viafb_SAMM_ON; +int viafb_dual_fb; +int viafb_hotplug_Xres = 640; +int viafb_hotplug_Yres = 480; +int viafb_hotplug_bpp = 32; +int viafb_hotplug_refresh = 60; +unsigned int viafb_second_offset; +int viafb_second_size; +int viafb_primary_dev = None_Device; +void __iomem *viafb_FB_MM; +unsigned int viafb_second_xres = 640; +unsigned int viafb_second_yres = 480; +unsigned int viafb_second_virtual_xres; +unsigned int viafb_second_virtual_yres; +int viafb_lcd_panel_id = LCD_PANEL_ID_MAXIMUM + 1; +struct fb_cursor viacursor; +struct fb_info *viafbinfo; +struct fb_info *viafbinfo1; +struct viafb_par *viaparinfo; +struct viafb_par *viaparinfo1; + diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h new file mode 100644 index 00000000000..8e5263c5b81 --- /dev/null +++ b/drivers/video/via/global.h @@ -0,0 +1,90 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GLOBAL_H__ +#define __GLOBAL_H__ + +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/console.h> +#include <linux/timer.h> + +#include "debug.h" + +#include "iface.h" +#include "viafbdev.h" +#include "chip.h" +#include "debug.h" +#include "accel.h" +#include "share.h" +#include "dvi.h" +#include "viamode.h" +#include "via_i2c.h" +#include "hw.h" + +#include "lcd.h" +#include "ioctl.h" +#include "viamode.h" +#include "via_utility.h" +#include "vt1636.h" +#include "tblDPASetting.h" +#include "tbl1636.h" +#include "viafbdev.h" + +/* External struct*/ + +extern int viafb_platform_epia_dvi; +extern int viafb_device_lcd_dualedge; +extern int viafb_bus_width; +extern int viafb_display_hardware_layout; +extern struct offset offset_reg; +extern struct viafb_par *viaparinfo; +extern struct viafb_par *viaparinfo1; +extern struct fb_info *viafbinfo; +extern struct fb_info *viafbinfo1; +extern int viafb_DeviceStatus; +extern int viafb_refresh; +extern int viafb_refresh1; +extern int viafb_lcd_dsp_method; +extern int viafb_lcd_mode; +extern int viafb_bpp; +extern int viafb_bpp1; + +extern int viafb_CRT_ON; +extern int viafb_hotplug_Xres; +extern int viafb_hotplug_Yres; +extern int viafb_hotplug_bpp; +extern int viafb_hotplug_refresh; +extern int viafb_primary_dev; +extern void __iomem *viafb_FB_MM; +extern struct fb_cursor viacursor; + +extern unsigned int viafb_second_xres; +extern unsigned int viafb_second_yres; +extern int viafb_lcd_panel_id; + +#endif /* __GLOBAL_H__ */ diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c new file mode 100644 index 00000000000..fcd53ceb88f --- /dev/null +++ b/drivers/video/via/hw.c @@ -0,0 +1,2865 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" + +static const struct pci_device_id_info pciidlist[] = { + {PCI_VIA_VENDOR_ID, UNICHROME_CLE266_DID, UNICHROME_CLE266}, + {PCI_VIA_VENDOR_ID, UNICHROME_PM800_DID, UNICHROME_PM800}, + {PCI_VIA_VENDOR_ID, UNICHROME_K400_DID, UNICHROME_K400}, + {PCI_VIA_VENDOR_ID, UNICHROME_K800_DID, UNICHROME_K800}, + {PCI_VIA_VENDOR_ID, UNICHROME_CN700_DID, UNICHROME_CN700}, + {PCI_VIA_VENDOR_ID, UNICHROME_P4M890_DID, UNICHROME_P4M890}, + {PCI_VIA_VENDOR_ID, UNICHROME_K8M890_DID, UNICHROME_K8M890}, + {PCI_VIA_VENDOR_ID, UNICHROME_CX700_DID, UNICHROME_CX700}, + {PCI_VIA_VENDOR_ID, UNICHROME_P4M900_DID, UNICHROME_P4M900}, + {PCI_VIA_VENDOR_ID, UNICHROME_CN750_DID, UNICHROME_CN750}, + {PCI_VIA_VENDOR_ID, UNICHROME_VX800_DID, UNICHROME_VX800}, + {0, 0, 0} +}; + +struct offset offset_reg = { + /* IGA1 Offset Register */ + {IGA1_OFFSET_REG_NUM, {{CR13, 0, 7}, {CR35, 5, 7} } }, + /* IGA2 Offset Register */ + {IGA2_OFFSET_REG_NUM, {{CR66, 0, 7}, {CR67, 0, 1} } } +}; + +static struct pll_map pll_value[] = { + {CLK_25_175M, CLE266_PLL_25_175M, K800_PLL_25_175M, CX700_25_175M}, + {CLK_29_581M, CLE266_PLL_29_581M, K800_PLL_29_581M, CX700_29_581M}, + {CLK_26_880M, CLE266_PLL_26_880M, K800_PLL_26_880M, CX700_26_880M}, + {CLK_31_490M, CLE266_PLL_31_490M, K800_PLL_31_490M, CX700_31_490M}, + {CLK_31_500M, CLE266_PLL_31_500M, K800_PLL_31_500M, CX700_31_500M}, + {CLK_31_728M, CLE266_PLL_31_728M, K800_PLL_31_728M, CX700_31_728M}, + {CLK_32_668M, CLE266_PLL_32_668M, K800_PLL_32_668M, CX700_32_668M}, + {CLK_36_000M, CLE266_PLL_36_000M, K800_PLL_36_000M, CX700_36_000M}, + {CLK_40_000M, CLE266_PLL_40_000M, K800_PLL_40_000M, CX700_40_000M}, + {CLK_41_291M, CLE266_PLL_41_291M, K800_PLL_41_291M, CX700_41_291M}, + {CLK_43_163M, CLE266_PLL_43_163M, K800_PLL_43_163M, CX700_43_163M}, + {CLK_45_250M, CLE266_PLL_45_250M, K800_PLL_45_250M, CX700_45_250M}, + {CLK_46_000M, CLE266_PLL_46_000M, K800_PLL_46_000M, CX700_46_000M}, + {CLK_46_996M, CLE266_PLL_46_996M, K800_PLL_46_996M, CX700_46_996M}, + {CLK_48_000M, CLE266_PLL_48_000M, K800_PLL_48_000M, CX700_48_000M}, + {CLK_48_875M, CLE266_PLL_48_875M, K800_PLL_48_875M, CX700_48_875M}, + {CLK_49_500M, CLE266_PLL_49_500M, K800_PLL_49_500M, CX700_49_500M}, + {CLK_52_406M, CLE266_PLL_52_406M, K800_PLL_52_406M, CX700_52_406M}, + {CLK_52_977M, CLE266_PLL_52_977M, K800_PLL_52_977M, CX700_52_977M}, + {CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M, CX700_56_250M}, + {CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M, CX700_60_466M}, + {CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M, CX700_61_500M}, + {CLK_65_000M, CLE266_PLL_65_000M, K800_PLL_65_000M, CX700_65_000M}, + {CLK_65_178M, CLE266_PLL_65_178M, K800_PLL_65_178M, CX700_65_178M}, + {CLK_66_750M, CLE266_PLL_66_750M, K800_PLL_66_750M, CX700_66_750M}, + {CLK_68_179M, CLE266_PLL_68_179M, K800_PLL_68_179M, CX700_68_179M}, + {CLK_69_924M, CLE266_PLL_69_924M, K800_PLL_69_924M, CX700_69_924M}, + {CLK_70_159M, CLE266_PLL_70_159M, K800_PLL_70_159M, CX700_70_159M}, + {CLK_72_000M, CLE266_PLL_72_000M, K800_PLL_72_000M, CX700_72_000M}, + {CLK_78_750M, CLE266_PLL_78_750M, K800_PLL_78_750M, CX700_78_750M}, + {CLK_80_136M, CLE266_PLL_80_136M, K800_PLL_80_136M, CX700_80_136M}, + {CLK_83_375M, CLE266_PLL_83_375M, K800_PLL_83_375M, CX700_83_375M}, + {CLK_83_950M, CLE266_PLL_83_950M, K800_PLL_83_950M, CX700_83_950M}, + {CLK_84_750M, CLE266_PLL_84_750M, K800_PLL_84_750M, CX700_84_750M}, + {CLK_85_860M, CLE266_PLL_85_860M, K800_PLL_85_860M, CX700_85_860M}, + {CLK_88_750M, CLE266_PLL_88_750M, K800_PLL_88_750M, CX700_88_750M}, + {CLK_94_500M, CLE266_PLL_94_500M, K800_PLL_94_500M, CX700_94_500M}, + {CLK_97_750M, CLE266_PLL_97_750M, K800_PLL_97_750M, CX700_97_750M}, + {CLK_101_000M, CLE266_PLL_101_000M, K800_PLL_101_000M, + CX700_101_000M}, + {CLK_106_500M, CLE266_PLL_106_500M, K800_PLL_106_500M, + CX700_106_500M}, + {CLK_108_000M, CLE266_PLL_108_000M, K800_PLL_108_000M, + CX700_108_000M}, + {CLK_113_309M, CLE266_PLL_113_309M, K800_PLL_113_309M, + CX700_113_309M}, + {CLK_118_840M, CLE266_PLL_118_840M, K800_PLL_118_840M, + CX700_118_840M}, + {CLK_119_000M, CLE266_PLL_119_000M, K800_PLL_119_000M, + CX700_119_000M}, + {CLK_121_750M, CLE266_PLL_121_750M, K800_PLL_121_750M, + CX700_121_750M}, + {CLK_125_104M, CLE266_PLL_125_104M, K800_PLL_125_104M, + CX700_125_104M}, + {CLK_133_308M, CLE266_PLL_133_308M, K800_PLL_133_308M, + CX700_133_308M}, + {CLK_135_000M, CLE266_PLL_135_000M, K800_PLL_135_000M, + CX700_135_000M}, + {CLK_136_700M, CLE266_PLL_136_700M, K800_PLL_136_700M, + CX700_136_700M}, + {CLK_138_400M, CLE266_PLL_138_400M, K800_PLL_138_400M, + CX700_138_400M}, + {CLK_146_760M, CLE266_PLL_146_760M, K800_PLL_146_760M, + CX700_146_760M}, + {CLK_153_920M, CLE266_PLL_153_920M, K800_PLL_153_920M, + CX700_153_920M}, + {CLK_156_000M, CLE266_PLL_156_000M, K800_PLL_156_000M, + CX700_156_000M}, + {CLK_157_500M, CLE266_PLL_157_500M, K800_PLL_157_500M, + CX700_157_500M}, + {CLK_162_000M, CLE266_PLL_162_000M, K800_PLL_162_000M, + CX700_162_000M}, + {CLK_187_000M, CLE266_PLL_187_000M, K800_PLL_187_000M, + CX700_187_000M}, + {CLK_193_295M, CLE266_PLL_193_295M, K800_PLL_193_295M, + CX700_193_295M}, + {CLK_202_500M, CLE266_PLL_202_500M, K800_PLL_202_500M, + CX700_202_500M}, + {CLK_204_000M, CLE266_PLL_204_000M, K800_PLL_204_000M, + CX700_204_000M}, + {CLK_218_500M, CLE266_PLL_218_500M, K800_PLL_218_500M, + CX700_218_500M}, + {CLK_234_000M, CLE266_PLL_234_000M, K800_PLL_234_000M, + CX700_234_000M}, + {CLK_267_250M, CLE266_PLL_267_250M, K800_PLL_267_250M, + CX700_267_250M}, + {CLK_297_500M, CLE266_PLL_297_500M, K800_PLL_297_500M, + CX700_297_500M}, + {CLK_74_481M, CLE266_PLL_74_481M, K800_PLL_74_481M, CX700_74_481M}, + {CLK_172_798M, CLE266_PLL_172_798M, K800_PLL_172_798M, + CX700_172_798M}, + {CLK_122_614M, CLE266_PLL_122_614M, K800_PLL_122_614M, + CX700_122_614M}, + {CLK_74_270M, CLE266_PLL_74_270M, K800_PLL_74_270M, CX700_74_270M}, + {CLK_148_500M, CLE266_PLL_148_500M, K800_PLL_148_500M, + CX700_148_500M} +}; + +static struct fifo_depth_select display_fifo_depth_reg = { + /* IGA1 FIFO Depth_Select */ + {IGA1_FIFO_DEPTH_SELECT_REG_NUM, {{SR17, 0, 7} } }, + /* IGA2 FIFO Depth_Select */ + {IGA2_FIFO_DEPTH_SELECT_REG_NUM, + {{CR68, 4, 7}, {CR94, 7, 7}, {CR95, 7, 7} } } +}; + +static struct fifo_threshold_select fifo_threshold_select_reg = { + /* IGA1 FIFO Threshold Select */ + {IGA1_FIFO_THRESHOLD_REG_NUM, {{SR16, 0, 5}, {SR16, 7, 7} } }, + /* IGA2 FIFO Threshold Select */ + {IGA2_FIFO_THRESHOLD_REG_NUM, {{CR68, 0, 3}, {CR95, 4, 6} } } +}; + +static struct fifo_high_threshold_select fifo_high_threshold_select_reg = { + /* IGA1 FIFO High Threshold Select */ + {IGA1_FIFO_HIGH_THRESHOLD_REG_NUM, {{SR18, 0, 5}, {SR18, 7, 7} } }, + /* IGA2 FIFO High Threshold Select */ + {IGA2_FIFO_HIGH_THRESHOLD_REG_NUM, {{CR92, 0, 3}, {CR95, 0, 2} } } +}; + +static struct display_queue_expire_num display_queue_expire_num_reg = { + /* IGA1 Display Queue Expire Num */ + {IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM, {{SR22, 0, 4} } }, + /* IGA2 Display Queue Expire Num */ + {IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM, {{CR94, 0, 6} } } +}; + +/* Definition Fetch Count Registers*/ +static struct fetch_count fetch_count_reg = { + /* IGA1 Fetch Count Register */ + {IGA1_FETCH_COUNT_REG_NUM, {{SR1C, 0, 7}, {SR1D, 0, 1} } }, + /* IGA2 Fetch Count Register */ + {IGA2_FETCH_COUNT_REG_NUM, {{CR65, 0, 7}, {CR67, 2, 3} } } +}; + +static struct iga1_crtc_timing iga1_crtc_reg = { + /* IGA1 Horizontal Total */ + {IGA1_HOR_TOTAL_REG_NUM, {{CR00, 0, 7}, {CR36, 3, 3} } }, + /* IGA1 Horizontal Addressable Video */ + {IGA1_HOR_ADDR_REG_NUM, {{CR01, 0, 7} } }, + /* IGA1 Horizontal Blank Start */ + {IGA1_HOR_BLANK_START_REG_NUM, {{CR02, 0, 7} } }, + /* IGA1 Horizontal Blank End */ + {IGA1_HOR_BLANK_END_REG_NUM, + {{CR03, 0, 4}, {CR05, 7, 7}, {CR33, 5, 5} } }, + /* IGA1 Horizontal Sync Start */ + {IGA1_HOR_SYNC_START_REG_NUM, {{CR04, 0, 7}, {CR33, 4, 4} } }, + /* IGA1 Horizontal Sync End */ + {IGA1_HOR_SYNC_END_REG_NUM, {{CR05, 0, 4} } }, + /* IGA1 Vertical Total */ + {IGA1_VER_TOTAL_REG_NUM, + {{CR06, 0, 7}, {CR07, 0, 0}, {CR07, 5, 5}, {CR35, 0, 0} } }, + /* IGA1 Vertical Addressable Video */ + {IGA1_VER_ADDR_REG_NUM, + {{CR12, 0, 7}, {CR07, 1, 1}, {CR07, 6, 6}, {CR35, 2, 2} } }, + /* IGA1 Vertical Blank Start */ + {IGA1_VER_BLANK_START_REG_NUM, + {{CR15, 0, 7}, {CR07, 3, 3}, {CR09, 5, 5}, {CR35, 3, 3} } }, + /* IGA1 Vertical Blank End */ + {IGA1_VER_BLANK_END_REG_NUM, {{CR16, 0, 7} } }, + /* IGA1 Vertical Sync Start */ + {IGA1_VER_SYNC_START_REG_NUM, + {{CR10, 0, 7}, {CR07, 2, 2}, {CR07, 7, 7}, {CR35, 1, 1} } }, + /* IGA1 Vertical Sync End */ + {IGA1_VER_SYNC_END_REG_NUM, {{CR11, 0, 3} } } +}; + +static struct iga2_crtc_timing iga2_crtc_reg = { + /* IGA2 Horizontal Total */ + {IGA2_HOR_TOTAL_REG_NUM, {{CR50, 0, 7}, {CR55, 0, 3} } }, + /* IGA2 Horizontal Addressable Video */ + {IGA2_HOR_ADDR_REG_NUM, {{CR51, 0, 7}, {CR55, 4, 6} } }, + /* IGA2 Horizontal Blank Start */ + {IGA2_HOR_BLANK_START_REG_NUM, {{CR52, 0, 7}, {CR54, 0, 2} } }, + /* IGA2 Horizontal Blank End */ + {IGA2_HOR_BLANK_END_REG_NUM, + {{CR53, 0, 7}, {CR54, 3, 5}, {CR5D, 6, 6} } }, + /* IGA2 Horizontal Sync Start */ + {IGA2_HOR_SYNC_START_REG_NUM, + {{CR56, 0, 7}, {CR54, 6, 7}, {CR5C, 7, 7}, {CR5D, 7, 7} } }, + /* IGA2 Horizontal Sync End */ + {IGA2_HOR_SYNC_END_REG_NUM, {{CR57, 0, 7}, {CR5C, 6, 6} } }, + /* IGA2 Vertical Total */ + {IGA2_VER_TOTAL_REG_NUM, {{CR58, 0, 7}, {CR5D, 0, 2} } }, + /* IGA2 Vertical Addressable Video */ + {IGA2_VER_ADDR_REG_NUM, {{CR59, 0, 7}, {CR5D, 3, 5} } }, + /* IGA2 Vertical Blank Start */ + {IGA2_VER_BLANK_START_REG_NUM, {{CR5A, 0, 7}, {CR5C, 0, 2} } }, + /* IGA2 Vertical Blank End */ + {IGA2_VER_BLANK_END_REG_NUM, {{CR5B, 0, 7}, {CR5C, 3, 5} } }, + /* IGA2 Vertical Sync Start */ + {IGA2_VER_SYNC_START_REG_NUM, {{CR5E, 0, 7}, {CR5F, 5, 7} } }, + /* IGA2 Vertical Sync End */ + {IGA2_VER_SYNC_END_REG_NUM, {{CR5F, 0, 4} } } +}; + +static struct rgbLUT palLUT_table[] = { + /* {R,G,B} */ + /* Index 0x00~0x03 */ + {0x00, 0x00, 0x00}, {0x00, 0x00, 0x2A}, {0x00, 0x2A, 0x00}, {0x00, + 0x2A, + 0x2A}, + /* Index 0x04~0x07 */ + {0x2A, 0x00, 0x00}, {0x2A, 0x00, 0x2A}, {0x2A, 0x15, 0x00}, {0x2A, + 0x2A, + 0x2A}, + /* Index 0x08~0x0B */ + {0x15, 0x15, 0x15}, {0x15, 0x15, 0x3F}, {0x15, 0x3F, 0x15}, {0x15, + 0x3F, + 0x3F}, + /* Index 0x0C~0x0F */ + {0x3F, 0x15, 0x15}, {0x3F, 0x15, 0x3F}, {0x3F, 0x3F, 0x15}, {0x3F, + 0x3F, + 0x3F}, + /* Index 0x10~0x13 */ + {0x00, 0x00, 0x00}, {0x05, 0x05, 0x05}, {0x08, 0x08, 0x08}, {0x0B, + 0x0B, + 0x0B}, + /* Index 0x14~0x17 */ + {0x0E, 0x0E, 0x0E}, {0x11, 0x11, 0x11}, {0x14, 0x14, 0x14}, {0x18, + 0x18, + 0x18}, + /* Index 0x18~0x1B */ + {0x1C, 0x1C, 0x1C}, {0x20, 0x20, 0x20}, {0x24, 0x24, 0x24}, {0x28, + 0x28, + 0x28}, + /* Index 0x1C~0x1F */ + {0x2D, 0x2D, 0x2D}, {0x32, 0x32, 0x32}, {0x38, 0x38, 0x38}, {0x3F, + 0x3F, + 0x3F}, + /* Index 0x20~0x23 */ + {0x00, 0x00, 0x3F}, {0x10, 0x00, 0x3F}, {0x1F, 0x00, 0x3F}, {0x2F, + 0x00, + 0x3F}, + /* Index 0x24~0x27 */ + {0x3F, 0x00, 0x3F}, {0x3F, 0x00, 0x2F}, {0x3F, 0x00, 0x1F}, {0x3F, + 0x00, + 0x10}, + /* Index 0x28~0x2B */ + {0x3F, 0x00, 0x00}, {0x3F, 0x10, 0x00}, {0x3F, 0x1F, 0x00}, {0x3F, + 0x2F, + 0x00}, + /* Index 0x2C~0x2F */ + {0x3F, 0x3F, 0x00}, {0x2F, 0x3F, 0x00}, {0x1F, 0x3F, 0x00}, {0x10, + 0x3F, + 0x00}, + /* Index 0x30~0x33 */ + {0x00, 0x3F, 0x00}, {0x00, 0x3F, 0x10}, {0x00, 0x3F, 0x1F}, {0x00, + 0x3F, + 0x2F}, + /* Index 0x34~0x37 */ + {0x00, 0x3F, 0x3F}, {0x00, 0x2F, 0x3F}, {0x00, 0x1F, 0x3F}, {0x00, + 0x10, + 0x3F}, + /* Index 0x38~0x3B */ + {0x1F, 0x1F, 0x3F}, {0x27, 0x1F, 0x3F}, {0x2F, 0x1F, 0x3F}, {0x37, + 0x1F, + 0x3F}, + /* Index 0x3C~0x3F */ + {0x3F, 0x1F, 0x3F}, {0x3F, 0x1F, 0x37}, {0x3F, 0x1F, 0x2F}, {0x3F, + 0x1F, + 0x27}, + /* Index 0x40~0x43 */ + {0x3F, 0x1F, 0x1F}, {0x3F, 0x27, 0x1F}, {0x3F, 0x2F, 0x1F}, {0x3F, + 0x3F, + 0x1F}, + /* Index 0x44~0x47 */ + {0x3F, 0x3F, 0x1F}, {0x37, 0x3F, 0x1F}, {0x2F, 0x3F, 0x1F}, {0x27, + 0x3F, + 0x1F}, + /* Index 0x48~0x4B */ + {0x1F, 0x3F, 0x1F}, {0x1F, 0x3F, 0x27}, {0x1F, 0x3F, 0x2F}, {0x1F, + 0x3F, + 0x37}, + /* Index 0x4C~0x4F */ + {0x1F, 0x3F, 0x3F}, {0x1F, 0x37, 0x3F}, {0x1F, 0x2F, 0x3F}, {0x1F, + 0x27, + 0x3F}, + /* Index 0x50~0x53 */ + {0x2D, 0x2D, 0x3F}, {0x31, 0x2D, 0x3F}, {0x36, 0x2D, 0x3F}, {0x3A, + 0x2D, + 0x3F}, + /* Index 0x54~0x57 */ + {0x3F, 0x2D, 0x3F}, {0x3F, 0x2D, 0x3A}, {0x3F, 0x2D, 0x36}, {0x3F, + 0x2D, + 0x31}, + /* Index 0x58~0x5B */ + {0x3F, 0x2D, 0x2D}, {0x3F, 0x31, 0x2D}, {0x3F, 0x36, 0x2D}, {0x3F, + 0x3A, + 0x2D}, + /* Index 0x5C~0x5F */ + {0x3F, 0x3F, 0x2D}, {0x3A, 0x3F, 0x2D}, {0x36, 0x3F, 0x2D}, {0x31, + 0x3F, + 0x2D}, + /* Index 0x60~0x63 */ + {0x2D, 0x3F, 0x2D}, {0x2D, 0x3F, 0x31}, {0x2D, 0x3F, 0x36}, {0x2D, + 0x3F, + 0x3A}, + /* Index 0x64~0x67 */ + {0x2D, 0x3F, 0x3F}, {0x2D, 0x3A, 0x3F}, {0x2D, 0x36, 0x3F}, {0x2D, + 0x31, + 0x3F}, + /* Index 0x68~0x6B */ + {0x00, 0x00, 0x1C}, {0x07, 0x00, 0x1C}, {0x0E, 0x00, 0x1C}, {0x15, + 0x00, + 0x1C}, + /* Index 0x6C~0x6F */ + {0x1C, 0x00, 0x1C}, {0x1C, 0x00, 0x15}, {0x1C, 0x00, 0x0E}, {0x1C, + 0x00, + 0x07}, + /* Index 0x70~0x73 */ + {0x1C, 0x00, 0x00}, {0x1C, 0x07, 0x00}, {0x1C, 0x0E, 0x00}, {0x1C, + 0x15, + 0x00}, + /* Index 0x74~0x77 */ + {0x1C, 0x1C, 0x00}, {0x15, 0x1C, 0x00}, {0x0E, 0x1C, 0x00}, {0x07, + 0x1C, + 0x00}, + /* Index 0x78~0x7B */ + {0x00, 0x1C, 0x00}, {0x00, 0x1C, 0x07}, {0x00, 0x1C, 0x0E}, {0x00, + 0x1C, + 0x15}, + /* Index 0x7C~0x7F */ + {0x00, 0x1C, 0x1C}, {0x00, 0x15, 0x1C}, {0x00, 0x0E, 0x1C}, {0x00, + 0x07, + 0x1C}, + /* Index 0x80~0x83 */ + {0x0E, 0x0E, 0x1C}, {0x11, 0x0E, 0x1C}, {0x15, 0x0E, 0x1C}, {0x18, + 0x0E, + 0x1C}, + /* Index 0x84~0x87 */ + {0x1C, 0x0E, 0x1C}, {0x1C, 0x0E, 0x18}, {0x1C, 0x0E, 0x15}, {0x1C, + 0x0E, + 0x11}, + /* Index 0x88~0x8B */ + {0x1C, 0x0E, 0x0E}, {0x1C, 0x11, 0x0E}, {0x1C, 0x15, 0x0E}, {0x1C, + 0x18, + 0x0E}, + /* Index 0x8C~0x8F */ + {0x1C, 0x1C, 0x0E}, {0x18, 0x1C, 0x0E}, {0x15, 0x1C, 0x0E}, {0x11, + 0x1C, + 0x0E}, + /* Index 0x90~0x93 */ + {0x0E, 0x1C, 0x0E}, {0x0E, 0x1C, 0x11}, {0x0E, 0x1C, 0x15}, {0x0E, + 0x1C, + 0x18}, + /* Index 0x94~0x97 */ + {0x0E, 0x1C, 0x1C}, {0x0E, 0x18, 0x1C}, {0x0E, 0x15, 0x1C}, {0x0E, + 0x11, + 0x1C}, + /* Index 0x98~0x9B */ + {0x14, 0x14, 0x1C}, {0x16, 0x14, 0x1C}, {0x18, 0x14, 0x1C}, {0x1A, + 0x14, + 0x1C}, + /* Index 0x9C~0x9F */ + {0x1C, 0x14, 0x1C}, {0x1C, 0x14, 0x1A}, {0x1C, 0x14, 0x18}, {0x1C, + 0x14, + 0x16}, + /* Index 0xA0~0xA3 */ + {0x1C, 0x14, 0x14}, {0x1C, 0x16, 0x14}, {0x1C, 0x18, 0x14}, {0x1C, + 0x1A, + 0x14}, + /* Index 0xA4~0xA7 */ + {0x1C, 0x1C, 0x14}, {0x1A, 0x1C, 0x14}, {0x18, 0x1C, 0x14}, {0x16, + 0x1C, + 0x14}, + /* Index 0xA8~0xAB */ + {0x14, 0x1C, 0x14}, {0x14, 0x1C, 0x16}, {0x14, 0x1C, 0x18}, {0x14, + 0x1C, + 0x1A}, + /* Index 0xAC~0xAF */ + {0x14, 0x1C, 0x1C}, {0x14, 0x1A, 0x1C}, {0x14, 0x18, 0x1C}, {0x14, + 0x16, + 0x1C}, + /* Index 0xB0~0xB3 */ + {0x00, 0x00, 0x10}, {0x04, 0x00, 0x10}, {0x08, 0x00, 0x10}, {0x0C, + 0x00, + 0x10}, + /* Index 0xB4~0xB7 */ + {0x10, 0x00, 0x10}, {0x10, 0x00, 0x0C}, {0x10, 0x00, 0x08}, {0x10, + 0x00, + 0x04}, + /* Index 0xB8~0xBB */ + {0x10, 0x00, 0x00}, {0x10, 0x04, 0x00}, {0x10, 0x08, 0x00}, {0x10, + 0x0C, + 0x00}, + /* Index 0xBC~0xBF */ + {0x10, 0x10, 0x00}, {0x0C, 0x10, 0x00}, {0x08, 0x10, 0x00}, {0x04, + 0x10, + 0x00}, + /* Index 0xC0~0xC3 */ + {0x00, 0x10, 0x00}, {0x00, 0x10, 0x04}, {0x00, 0x10, 0x08}, {0x00, + 0x10, + 0x0C}, + /* Index 0xC4~0xC7 */ + {0x00, 0x10, 0x10}, {0x00, 0x0C, 0x10}, {0x00, 0x08, 0x10}, {0x00, + 0x04, + 0x10}, + /* Index 0xC8~0xCB */ + {0x08, 0x08, 0x10}, {0x0A, 0x08, 0x10}, {0x0C, 0x08, 0x10}, {0x0E, + 0x08, + 0x10}, + /* Index 0xCC~0xCF */ + {0x10, 0x08, 0x10}, {0x10, 0x08, 0x0E}, {0x10, 0x08, 0x0C}, {0x10, + 0x08, + 0x0A}, + /* Index 0xD0~0xD3 */ + {0x10, 0x08, 0x08}, {0x10, 0x0A, 0x08}, {0x10, 0x0C, 0x08}, {0x10, + 0x0E, + 0x08}, + /* Index 0xD4~0xD7 */ + {0x10, 0x10, 0x08}, {0x0E, 0x10, 0x08}, {0x0C, 0x10, 0x08}, {0x0A, + 0x10, + 0x08}, + /* Index 0xD8~0xDB */ + {0x08, 0x10, 0x08}, {0x08, 0x10, 0x0A}, {0x08, 0x10, 0x0C}, {0x08, + 0x10, + 0x0E}, + /* Index 0xDC~0xDF */ + {0x08, 0x10, 0x10}, {0x08, 0x0E, 0x10}, {0x08, 0x0C, 0x10}, {0x08, + 0x0A, + 0x10}, + /* Index 0xE0~0xE3 */ + {0x0B, 0x0B, 0x10}, {0x0C, 0x0B, 0x10}, {0x0D, 0x0B, 0x10}, {0x0F, + 0x0B, + 0x10}, + /* Index 0xE4~0xE7 */ + {0x10, 0x0B, 0x10}, {0x10, 0x0B, 0x0F}, {0x10, 0x0B, 0x0D}, {0x10, + 0x0B, + 0x0C}, + /* Index 0xE8~0xEB */ + {0x10, 0x0B, 0x0B}, {0x10, 0x0C, 0x0B}, {0x10, 0x0D, 0x0B}, {0x10, + 0x0F, + 0x0B}, + /* Index 0xEC~0xEF */ + {0x10, 0x10, 0x0B}, {0x0F, 0x10, 0x0B}, {0x0D, 0x10, 0x0B}, {0x0C, + 0x10, + 0x0B}, + /* Index 0xF0~0xF3 */ + {0x0B, 0x10, 0x0B}, {0x0B, 0x10, 0x0C}, {0x0B, 0x10, 0x0D}, {0x0B, + 0x10, + 0x0F}, + /* Index 0xF4~0xF7 */ + {0x0B, 0x10, 0x10}, {0x0B, 0x0F, 0x10}, {0x0B, 0x0D, 0x10}, {0x0B, + 0x0C, + 0x10}, + /* Index 0xF8~0xFB */ + {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, + 0x00, + 0x00}, + /* Index 0xFC~0xFF */ + {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, + 0x00, + 0x00} +}; + +static void set_crt_output_path(int set_iga); +static void dvi_patch_skew_dvp0(void); +static void dvi_patch_skew_dvp1(void); +static void dvi_patch_skew_dvp_low(void); +static void set_dvi_output_path(int set_iga, int output_interface); +static void set_lcd_output_path(int set_iga, int output_interface); +static int search_mode_setting(int ModeInfoIndex); +static void load_fix_bit_crtc_reg(void); +static void init_gfx_chip_info(void); +static void init_tmds_chip_info(void); +static void init_lvds_chip_info(void); +static void device_screen_off(void); +static void device_screen_on(void); +static void set_display_channel(void); +static void device_off(void); +static void device_on(void); +static void enable_second_display_channel(void); +static void disable_second_display_channel(void); +static int get_fb_size_from_pci(void); + +void viafb_write_reg(u8 index, u16 io_port, u8 data) +{ + outb(index, io_port); + outb(data, io_port + 1); + /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, data); */ +} +u8 viafb_read_reg(int io_port, u8 index) +{ + outb(index, io_port); + return inb(io_port + 1); +} + +void viafb_lock_crt(void) +{ + viafb_write_reg_mask(CR11, VIACR, BIT7, BIT7); +} + +void viafb_unlock_crt(void) +{ + viafb_write_reg_mask(CR11, VIACR, 0, BIT7); + viafb_write_reg_mask(CR47, VIACR, 0, BIT0); +} + +void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask) +{ + u8 tmp; + + outb(index, io_port); + tmp = inb(io_port + 1); + outb((data & mask) | (tmp & (~mask)), io_port + 1); + /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, tmp); */ +} + +void write_dac_reg(u8 index, u8 r, u8 g, u8 b) +{ + outb(index, LUT_INDEX_WRITE); + outb(r, LUT_DATA); + outb(g, LUT_DATA); + outb(b, LUT_DATA); +} + +/*Set IGA path for each device*/ +void viafb_set_iga_path(void) +{ + + if (viafb_SAMM_ON == 1) { + if (viafb_CRT_ON) { + if (viafb_primary_dev == CRT_Device) + viaparinfo->crt_setting_info->iga_path = IGA1; + else + viaparinfo->crt_setting_info->iga_path = IGA2; + } + + if (viafb_DVI_ON) { + if (viafb_primary_dev == DVI_Device) + viaparinfo->tmds_setting_info->iga_path = IGA1; + else + viaparinfo->tmds_setting_info->iga_path = IGA2; + } + + if (viafb_LCD_ON) { + if (viafb_primary_dev == LCD_Device) { + if (viafb_dual_fb && + (viaparinfo->chip_info->gfx_chip_name == + UNICHROME_CLE266)) { + viaparinfo-> + lvds_setting_info->iga_path = IGA2; + viaparinfo-> + crt_setting_info->iga_path = IGA1; + viaparinfo-> + tmds_setting_info->iga_path = IGA1; + } else + viaparinfo-> + lvds_setting_info->iga_path = IGA1; + } else { + viaparinfo->lvds_setting_info->iga_path = IGA2; + } + } + if (viafb_LCD2_ON) { + if (LCD2_Device == viafb_primary_dev) + viaparinfo->lvds_setting_info2->iga_path = IGA1; + else + viaparinfo->lvds_setting_info2->iga_path = IGA2; + } + } else { + viafb_SAMM_ON = 0; + + if (viafb_CRT_ON && viafb_LCD_ON) { + viaparinfo->crt_setting_info->iga_path = IGA1; + viaparinfo->lvds_setting_info->iga_path = IGA2; + } else if (viafb_CRT_ON && viafb_DVI_ON) { + viaparinfo->crt_setting_info->iga_path = IGA1; + viaparinfo->tmds_setting_info->iga_path = IGA2; + } else if (viafb_LCD_ON && viafb_DVI_ON) { + viaparinfo->tmds_setting_info->iga_path = IGA1; + viaparinfo->lvds_setting_info->iga_path = IGA2; + } else if (viafb_LCD_ON && viafb_LCD2_ON) { + viaparinfo->lvds_setting_info->iga_path = IGA2; + viaparinfo->lvds_setting_info2->iga_path = IGA2; + } else if (viafb_CRT_ON) { + viaparinfo->crt_setting_info->iga_path = IGA1; + } else if (viafb_LCD_ON) { + viaparinfo->lvds_setting_info->iga_path = IGA2; + } else if (viafb_DVI_ON) { + viaparinfo->tmds_setting_info->iga_path = IGA1; + } + } +} + +void viafb_set_start_addr(void) +{ + unsigned long offset = 0, tmp = 0, size = 0; + unsigned long length; + + DEBUG_MSG(KERN_INFO "viafb_set_start_addr!\n"); + viafb_unlock_crt(); + /* update starting address of IGA1 */ + viafb_write_reg(CR0C, VIACR, 0x00); /*initial starting address */ + viafb_write_reg(CR0D, VIACR, 0x00); + viafb_write_reg(CR34, VIACR, 0x00); + viafb_write_reg_mask(CR48, VIACR, 0x00, 0x1F); + + if (viafb_dual_fb) { + viaparinfo->iga_path = IGA1; + viaparinfo1->iga_path = IGA2; + } + + if (viafb_SAMM_ON == 1) { + if (!viafb_dual_fb) { + if (viafb_second_size) + size = viafb_second_size * 1024 * 1024; + else + size = 8 * 1024 * 1024; + } else { + + size = viaparinfo1->memsize; + } + offset = viafb_second_offset; + DEBUG_MSG(KERN_INFO + "viafb_second_size=%lx, second start_adddress=%lx\n", + size, offset); + } + if (viafb_SAMM_ON == 1) { + offset = offset >> 3; + + tmp = viafb_read_reg(VIACR, 0x62) & 0x01; + tmp |= (offset & 0x7F) << 1; + viafb_write_reg(CR62, VIACR, tmp); + viafb_write_reg(CR63, VIACR, ((offset & 0x7F80) >> 7)); + viafb_write_reg(CR64, VIACR, ((offset & 0x7F8000) >> 15)); + viafb_write_reg(CRA3, VIACR, ((offset & 0x3800000) >> 23)); + } else { + /* update starting address */ + viafb_write_reg(CR62, VIACR, 0x00); + viafb_write_reg(CR63, VIACR, 0x00); + viafb_write_reg(CR64, VIACR, 0x00); + viafb_write_reg(CRA3, VIACR, 0x00); + } + + if (viafb_SAMM_ON == 1) { + if (viafb_accel) { + if (!viafb_dual_fb) + length = size - viaparinfo->fbmem_used; + else + length = size - viaparinfo1->fbmem_used; + } else + length = size; + offset = (unsigned long)(void *)viafb_FB_MM + + viafb_second_offset; + memset((void *)offset, 0, length); + } + + viafb_lock_crt(); +} + +void viafb_set_output_path(int device, int set_iga, int output_interface) +{ + switch (device) { + case DEVICE_CRT: + set_crt_output_path(set_iga); + break; + case DEVICE_DVI: + set_dvi_output_path(set_iga, output_interface); + break; + case DEVICE_LCD: + set_lcd_output_path(set_iga, output_interface); + break; + } +} + +static void set_crt_output_path(int set_iga) +{ + viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5); + + switch (set_iga) { + case IGA1: + viafb_write_reg_mask(SR16, VIASR, 0x00, BIT6); + break; + case IGA2: + case IGA1_IGA2: + viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7); + viafb_write_reg_mask(SR16, VIASR, 0x40, BIT6); + if (set_iga == IGA1_IGA2) + viafb_write_reg_mask(CR6B, VIACR, 0x08, BIT3); + break; + } +} + +static void dvi_patch_skew_dvp0(void) +{ + /* Reset data driving first: */ + viafb_write_reg_mask(SR1B, VIASR, 0, BIT1); + viafb_write_reg_mask(SR2A, VIASR, 0, BIT4); + + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_P4M890: + { + if ((viaparinfo->tmds_setting_info->h_active == 1600) && + (viaparinfo->tmds_setting_info->v_active == + 1200)) + viafb_write_reg_mask(CR96, VIACR, 0x03, + BIT0 + BIT1 + BIT2); + else + viafb_write_reg_mask(CR96, VIACR, 0x07, + BIT0 + BIT1 + BIT2); + break; + } + + case UNICHROME_P4M900: + { + viafb_write_reg_mask(CR96, VIACR, 0x07, + BIT0 + BIT1 + BIT2 + BIT3); + viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1); + viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4); + break; + } + + default: + { + break; + } + } +} + +static void dvi_patch_skew_dvp1(void) +{ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CX700: + { + break; + } + + default: + { + break; + } + } +} + +static void dvi_patch_skew_dvp_low(void) +{ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + { + viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1); + break; + } + + case UNICHROME_P4M900: + { + viafb_write_reg_mask(CR99, VIACR, 0x08, + BIT0 + BIT1 + BIT2 + BIT3); + break; + } + + case UNICHROME_P4M890: + { + viafb_write_reg_mask(CR99, VIACR, 0x0F, + BIT0 + BIT1 + BIT2 + BIT3); + break; + } + + default: + { + break; + } + } +} + +static void set_dvi_output_path(int set_iga, int output_interface) +{ + switch (output_interface) { + case INTERFACE_DVP0: + viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0); + + if (set_iga == IGA1) { + viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4); + viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 + + BIT5 + BIT7); + } else { + viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4); + viafb_write_reg_mask(CR6C, VIACR, 0xA1, BIT0 + + BIT5 + BIT7); + } + + viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT7 + BIT6); + + dvi_patch_skew_dvp0(); + break; + + case INTERFACE_DVP1: + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { + if (set_iga == IGA1) + viafb_write_reg_mask(CR93, VIACR, 0x21, + BIT0 + BIT5 + BIT7); + else + viafb_write_reg_mask(CR93, VIACR, 0xA1, + BIT0 + BIT5 + BIT7); + } else { + if (set_iga == IGA1) + viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4); + else + viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4); + } + + viafb_write_reg_mask(SR1E, VIASR, 0x30, BIT4 + BIT5); + dvi_patch_skew_dvp1(); + break; + case INTERFACE_DFP_HIGH: + if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) { + if (set_iga == IGA1) { + viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4); + viafb_write_reg_mask(CR97, VIACR, 0x03, + BIT0 + BIT1 + BIT4); + } else { + viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4); + viafb_write_reg_mask(CR97, VIACR, 0x13, + BIT0 + BIT1 + BIT4); + } + } + viafb_write_reg_mask(SR2A, VIASR, 0x0C, BIT2 + BIT3); + break; + + case INTERFACE_DFP_LOW: + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + break; + + if (set_iga == IGA1) { + viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); + viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4); + } else { + viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); + viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4); + } + + viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1); + dvi_patch_skew_dvp_low(); + break; + + case INTERFACE_TMDS: + if (set_iga == IGA1) + viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); + else + viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); + break; + } + + if (set_iga == IGA2) { + enable_second_display_channel(); + /* Disable LCD Scaling */ + viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0); + } +} + +static void set_lcd_output_path(int set_iga, int output_interface) +{ + DEBUG_MSG(KERN_INFO + "set_lcd_output_path, iga:%d,out_interface:%d\n", + set_iga, output_interface); + switch (set_iga) { + case IGA1: + viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3); + viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); + + disable_second_display_channel(); + break; + + case IGA2: + viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3); + viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); + + enable_second_display_channel(); + break; + + case IGA1_IGA2: + viafb_write_reg_mask(CR6B, VIACR, 0x08, BIT3); + viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); + + disable_second_display_channel(); + break; + } + + switch (output_interface) { + case INTERFACE_DVP0: + if (set_iga == IGA1) { + viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4); + } else { + viafb_write_reg(CR91, VIACR, 0x00); + viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4); + } + break; + + case INTERFACE_DVP1: + if (set_iga == IGA1) + viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4); + else { + viafb_write_reg(CR91, VIACR, 0x00); + viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4); + } + break; + + case INTERFACE_DFP_HIGH: + if (set_iga == IGA1) + viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4); + else { + viafb_write_reg(CR91, VIACR, 0x00); + viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4); + viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4); + } + break; + + case INTERFACE_DFP_LOW: + if (set_iga == IGA1) + viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); + else { + viafb_write_reg(CR91, VIACR, 0x00); + viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); + viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4); + } + + break; + + case INTERFACE_DFP: + if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name) + || (UNICHROME_P4M890 == + viaparinfo->chip_info->gfx_chip_name)) + viafb_write_reg_mask(CR97, VIACR, 0x84, + BIT7 + BIT2 + BIT1 + BIT0); + if (set_iga == IGA1) { + viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4); + viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); + } else { + viafb_write_reg(CR91, VIACR, 0x00); + viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4); + viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); + } + break; + + case INTERFACE_LVDS0: + case INTERFACE_LVDS0LVDS1: + if (set_iga == IGA1) + viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); + else + viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); + + break; + + case INTERFACE_LVDS1: + if (set_iga == IGA1) + viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4); + else + viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4); + break; + } +} + +/* Search Mode Index */ +static int search_mode_setting(int ModeInfoIndex) +{ + int i = 0; + + while ((i < NUM_TOTAL_MODETABLE) && + (ModeInfoIndex != CLE266Modes[i].ModeIndex)) + i++; + if (i >= NUM_TOTAL_MODETABLE) + i = 0; + return i; + +} + +struct VideoModeTable *viafb_get_modetbl_pointer(int Index) +{ + struct VideoModeTable *TmpTbl = NULL; + TmpTbl = &CLE266Modes[search_mode_setting(Index)]; + return TmpTbl; +} + +struct VideoModeTable *viafb_get_cea_mode_tbl_pointer(int Index) +{ + struct VideoModeTable *TmpTbl = NULL; + int i = 0; + while ((i < NUM_TOTAL_CEA_MODES) && + (Index != CEA_HDMI_Modes[i].ModeIndex)) + i++; + if ((i < NUM_TOTAL_CEA_MODES)) + TmpTbl = &CEA_HDMI_Modes[i]; + else { + /*Still use general timing if don't find CEA timing */ + i = 0; + while ((i < NUM_TOTAL_MODETABLE) && + (Index != CLE266Modes[i].ModeIndex)) + i++; + if (i >= NUM_TOTAL_MODETABLE) + i = 0; + TmpTbl = &CLE266Modes[i]; + } + return TmpTbl; +} + +static void load_fix_bit_crtc_reg(void) +{ + /* always set to 1 */ + viafb_write_reg_mask(CR03, VIACR, 0x80, BIT7); + /* line compare should set all bits = 1 (extend modes) */ + viafb_write_reg(CR18, VIACR, 0xff); + /* line compare should set all bits = 1 (extend modes) */ + viafb_write_reg_mask(CR07, VIACR, 0x10, BIT4); + /* line compare should set all bits = 1 (extend modes) */ + viafb_write_reg_mask(CR09, VIACR, 0x40, BIT6); + /* line compare should set all bits = 1 (extend modes) */ + viafb_write_reg_mask(CR35, VIACR, 0x10, BIT4); + /* line compare should set all bits = 1 (extend modes) */ + viafb_write_reg_mask(CR33, VIACR, 0x06, BIT0 + BIT1 + BIT2); + /*viafb_write_reg_mask(CR32, VIACR, 0x01, BIT0); */ + /* extend mode always set to e3h */ + viafb_write_reg(CR17, VIACR, 0xe3); + /* extend mode always set to 0h */ + viafb_write_reg(CR08, VIACR, 0x00); + /* extend mode always set to 0h */ + viafb_write_reg(CR14, VIACR, 0x00); + + /* If K8M800, enable Prefetch Mode. */ + if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) + || (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890)) + viafb_write_reg_mask(CR33, VIACR, 0x08, BIT3); + if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + && (viaparinfo->chip_info->gfx_chip_revision == CLE266_REVISION_AX)) + viafb_write_reg_mask(SR1A, VIASR, 0x02, BIT1); + +} + +void viafb_load_reg(int timing_value, int viafb_load_reg_num, + struct io_register *reg, + int io_type) +{ + int reg_mask; + int bit_num = 0; + int data; + int i, j; + int shift_next_reg; + int start_index, end_index, cr_index; + u16 get_bit; + + for (i = 0; i < viafb_load_reg_num; i++) { + reg_mask = 0; + data = 0; + start_index = reg[i].start_bit; + end_index = reg[i].end_bit; + cr_index = reg[i].io_addr; + + shift_next_reg = bit_num; + for (j = start_index; j <= end_index; j++) { + /*if (bit_num==8) timing_value = timing_value >>8; */ + reg_mask = reg_mask | (BIT0 << j); + get_bit = (timing_value & (BIT0 << bit_num)); + data = + data | ((get_bit >> shift_next_reg) << start_index); + bit_num++; + } + if (io_type == VIACR) + viafb_write_reg_mask(cr_index, VIACR, data, reg_mask); + else + viafb_write_reg_mask(cr_index, VIASR, data, reg_mask); + } + +} + +/* Write Registers */ +void viafb_write_regx(struct io_reg RegTable[], int ItemNum) +{ + int i; + unsigned char RegTemp; + + /*DEBUG_MSG(KERN_INFO "Table Size : %x!!\n",ItemNum ); */ + + for (i = 0; i < ItemNum; i++) { + outb(RegTable[i].index, RegTable[i].port); + RegTemp = inb(RegTable[i].port + 1); + RegTemp = (RegTemp & (~RegTable[i].mask)) | RegTable[i].value; + outb(RegTemp, RegTable[i].port + 1); + } +} + +void viafb_load_offset_reg(int h_addr, int bpp_byte, int set_iga) +{ + int reg_value; + int viafb_load_reg_num; + struct io_register *reg; + + switch (set_iga) { + case IGA1_IGA2: + case IGA1: + reg_value = IGA1_OFFSET_FORMULA(h_addr, bpp_byte); + viafb_load_reg_num = offset_reg.iga1_offset_reg.reg_num; + reg = offset_reg.iga1_offset_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); + if (set_iga == IGA1) + break; + case IGA2: + reg_value = IGA2_OFFSET_FORMULA(h_addr, bpp_byte); + viafb_load_reg_num = offset_reg.iga2_offset_reg.reg_num; + reg = offset_reg.iga2_offset_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); + break; + } +} + +void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga) +{ + int reg_value; + int viafb_load_reg_num; + struct io_register *reg = NULL; + + switch (set_iga) { + case IGA1_IGA2: + case IGA1: + reg_value = IGA1_FETCH_COUNT_FORMULA(h_addr, bpp_byte); + viafb_load_reg_num = fetch_count_reg. + iga1_fetch_count_reg.reg_num; + reg = fetch_count_reg.iga1_fetch_count_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); + if (set_iga == IGA1) + break; + case IGA2: + reg_value = IGA2_FETCH_COUNT_FORMULA(h_addr, bpp_byte); + viafb_load_reg_num = fetch_count_reg. + iga2_fetch_count_reg.reg_num; + reg = fetch_count_reg.iga2_fetch_count_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); + break; + } + +} + +void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) +{ + int reg_value; + int viafb_load_reg_num; + struct io_register *reg = NULL; + int iga1_fifo_max_depth = 0, iga1_fifo_threshold = + 0, iga1_fifo_high_threshold = 0, iga1_display_queue_expire_num = 0; + int iga2_fifo_max_depth = 0, iga2_fifo_threshold = + 0, iga2_fifo_high_threshold = 0, iga2_display_queue_expire_num = 0; + + if (set_iga == IGA1) { + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) { + iga1_fifo_max_depth = K800_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = K800_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + K800_IGA1_FIFO_HIGH_THRESHOLD; + /* If resolution > 1280x1024, expire length = 64, else + expire length = 128 */ + if ((hor_active > 1280) && (ver_active > 1024)) + iga1_display_queue_expire_num = 16; + else + iga1_display_queue_expire_num = + K800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_PM800) { + iga1_fifo_max_depth = P880_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = P880_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + P880_IGA1_FIFO_HIGH_THRESHOLD; + iga1_display_queue_expire_num = + P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + + /* If resolution > 1280x1024, expire length = 64, else + expire length = 128 */ + if ((hor_active > 1280) && (ver_active > 1024)) + iga1_display_queue_expire_num = 16; + else + iga1_display_queue_expire_num = + P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CN700) { + iga1_fifo_max_depth = CN700_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = CN700_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + CN700_IGA1_FIFO_HIGH_THRESHOLD; + + /* If resolution > 1280x1024, expire length = 64, + else expire length = 128 */ + if ((hor_active > 1280) && (ver_active > 1024)) + iga1_display_queue_expire_num = 16; + else + iga1_display_queue_expire_num = + CN700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { + iga1_fifo_max_depth = CX700_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = CX700_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + CX700_IGA1_FIFO_HIGH_THRESHOLD; + iga1_display_queue_expire_num = + CX700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890) { + iga1_fifo_max_depth = K8M890_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = K8M890_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + K8M890_IGA1_FIFO_HIGH_THRESHOLD; + iga1_display_queue_expire_num = + K8M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M890) { + iga1_fifo_max_depth = P4M890_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = P4M890_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + P4M890_IGA1_FIFO_HIGH_THRESHOLD; + iga1_display_queue_expire_num = + P4M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M900) { + iga1_fifo_max_depth = P4M900_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = P4M900_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + P4M900_IGA1_FIFO_HIGH_THRESHOLD; + iga1_display_queue_expire_num = + P4M900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX800) { + iga1_fifo_max_depth = VX800_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = VX800_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + VX800_IGA1_FIFO_HIGH_THRESHOLD; + iga1_display_queue_expire_num = + VX800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + } + + /* Set Display FIFO Depath Select */ + reg_value = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth); + viafb_load_reg_num = + display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num; + reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); + + /* Set Display FIFO Threshold Select */ + reg_value = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold); + viafb_load_reg_num = + fifo_threshold_select_reg. + iga1_fifo_threshold_select_reg.reg_num; + reg = + fifo_threshold_select_reg. + iga1_fifo_threshold_select_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); + + /* Set FIFO High Threshold Select */ + reg_value = + IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold); + viafb_load_reg_num = + fifo_high_threshold_select_reg. + iga1_fifo_high_threshold_select_reg.reg_num; + reg = + fifo_high_threshold_select_reg. + iga1_fifo_high_threshold_select_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); + + /* Set Display Queue Expire Num */ + reg_value = + IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA + (iga1_display_queue_expire_num); + viafb_load_reg_num = + display_queue_expire_num_reg. + iga1_display_queue_expire_num_reg.reg_num; + reg = + display_queue_expire_num_reg. + iga1_display_queue_expire_num_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR); + + } else { + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) { + iga2_fifo_max_depth = K800_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = K800_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + K800_IGA2_FIFO_HIGH_THRESHOLD; + + /* If resolution > 1280x1024, expire length = 64, + else expire length = 128 */ + if ((hor_active > 1280) && (ver_active > 1024)) + iga2_display_queue_expire_num = 16; + else + iga2_display_queue_expire_num = + K800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_PM800) { + iga2_fifo_max_depth = P880_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = P880_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + P880_IGA2_FIFO_HIGH_THRESHOLD; + + /* If resolution > 1280x1024, expire length = 64, + else expire length = 128 */ + if ((hor_active > 1280) && (ver_active > 1024)) + iga2_display_queue_expire_num = 16; + else + iga2_display_queue_expire_num = + P880_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CN700) { + iga2_fifo_max_depth = CN700_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = CN700_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + CN700_IGA2_FIFO_HIGH_THRESHOLD; + + /* If resolution > 1280x1024, expire length = 64, + else expire length = 128 */ + if ((hor_active > 1280) && (ver_active > 1024)) + iga2_display_queue_expire_num = 16; + else + iga2_display_queue_expire_num = + CN700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { + iga2_fifo_max_depth = CX700_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = CX700_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + CX700_IGA2_FIFO_HIGH_THRESHOLD; + iga2_display_queue_expire_num = + CX700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890) { + iga2_fifo_max_depth = K8M890_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = K8M890_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + K8M890_IGA2_FIFO_HIGH_THRESHOLD; + iga2_display_queue_expire_num = + K8M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M890) { + iga2_fifo_max_depth = P4M890_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = P4M890_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + P4M890_IGA2_FIFO_HIGH_THRESHOLD; + iga2_display_queue_expire_num = + P4M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M900) { + iga2_fifo_max_depth = P4M900_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = P4M900_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + P4M900_IGA2_FIFO_HIGH_THRESHOLD; + iga2_display_queue_expire_num = + P4M900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX800) { + iga2_fifo_max_depth = VX800_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = VX800_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + VX800_IGA2_FIFO_HIGH_THRESHOLD; + iga2_display_queue_expire_num = + VX800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) { + /* Set Display FIFO Depath Select */ + reg_value = + IGA2_FIFO_DEPTH_SELECT_FORMULA(iga2_fifo_max_depth) + - 1; + /* Patch LCD in IGA2 case */ + viafb_load_reg_num = + display_fifo_depth_reg. + iga2_fifo_depth_select_reg.reg_num; + reg = + display_fifo_depth_reg. + iga2_fifo_depth_select_reg.reg; + viafb_load_reg(reg_value, + viafb_load_reg_num, reg, VIACR); + } else { + + /* Set Display FIFO Depath Select */ + reg_value = + IGA2_FIFO_DEPTH_SELECT_FORMULA(iga2_fifo_max_depth); + viafb_load_reg_num = + display_fifo_depth_reg. + iga2_fifo_depth_select_reg.reg_num; + reg = + display_fifo_depth_reg. + iga2_fifo_depth_select_reg.reg; + viafb_load_reg(reg_value, + viafb_load_reg_num, reg, VIACR); + } + + /* Set Display FIFO Threshold Select */ + reg_value = IGA2_FIFO_THRESHOLD_FORMULA(iga2_fifo_threshold); + viafb_load_reg_num = + fifo_threshold_select_reg. + iga2_fifo_threshold_select_reg.reg_num; + reg = + fifo_threshold_select_reg. + iga2_fifo_threshold_select_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); + + /* Set FIFO High Threshold Select */ + reg_value = + IGA2_FIFO_HIGH_THRESHOLD_FORMULA(iga2_fifo_high_threshold); + viafb_load_reg_num = + fifo_high_threshold_select_reg. + iga2_fifo_high_threshold_select_reg.reg_num; + reg = + fifo_high_threshold_select_reg. + iga2_fifo_high_threshold_select_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); + + /* Set Display Queue Expire Num */ + reg_value = + IGA2_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA + (iga2_display_queue_expire_num); + viafb_load_reg_num = + display_queue_expire_num_reg. + iga2_display_queue_expire_num_reg.reg_num; + reg = + display_queue_expire_num_reg. + iga2_display_queue_expire_num_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); + + } + +} + +u32 viafb_get_clk_value(int clk) +{ + int i; + + for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) { + if (clk == pll_value[i].clk) { + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + return pll_value[i].cle266_pll; + + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + return pll_value[i].k800_pll; + + case UNICHROME_CX700: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + case UNICHROME_P4M900: + case UNICHROME_VX800: + return pll_value[i].cx700_pll; + } + } + } + + DEBUG_MSG(KERN_INFO "Can't find match PLL value\n\n"); + return 0; +} + +/* Set VCLK*/ +void viafb_set_vclock(u32 CLK, int set_iga) +{ + unsigned char RegTemp; + + /* H.W. Reset : ON */ + viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); + + if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) { + /* Change D,N FOR VCLK */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + viafb_write_reg(SR46, VIASR, CLK / 0x100); + viafb_write_reg(SR47, VIASR, CLK % 0x100); + break; + + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + case UNICHROME_CX700: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + case UNICHROME_P4M900: + case UNICHROME_VX800: + viafb_write_reg(SR44, VIASR, CLK / 0x10000); + DEBUG_MSG(KERN_INFO "\nSR44=%x", CLK / 0x10000); + viafb_write_reg(SR45, VIASR, (CLK & 0xFFFF) / 0x100); + DEBUG_MSG(KERN_INFO "\nSR45=%x", + (CLK & 0xFFFF) / 0x100); + viafb_write_reg(SR46, VIASR, CLK % 0x100); + DEBUG_MSG(KERN_INFO "\nSR46=%x", CLK % 0x100); + break; + } + } + + if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) { + /* Change D,N FOR LCK */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + viafb_write_reg(SR44, VIASR, CLK / 0x100); + viafb_write_reg(SR45, VIASR, CLK % 0x100); + break; + + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + case UNICHROME_CX700: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + case UNICHROME_P4M900: + case UNICHROME_VX800: + viafb_write_reg(SR4A, VIASR, CLK / 0x10000); + viafb_write_reg(SR4B, VIASR, (CLK & 0xFFFF) / 0x100); + viafb_write_reg(SR4C, VIASR, CLK % 0x100); + break; + } + } + + /* H.W. Reset : OFF */ + viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); + + /* Reset PLL */ + if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) { + viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1); + viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1); + } + + if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) { + viafb_write_reg_mask(SR40, VIASR, 0x01, BIT0); + viafb_write_reg_mask(SR40, VIASR, 0x00, BIT0); + } + + /* Fire! */ + RegTemp = inb(VIARMisc); + outb(RegTemp | (BIT2 + BIT3), VIAWMisc); +} + +void viafb_load_crtc_timing(struct display_timing device_timing, + int set_iga) +{ + int i; + int viafb_load_reg_num = 0; + int reg_value = 0; + struct io_register *reg = NULL; + + viafb_unlock_crt(); + + for (i = 0; i < 12; i++) { + if (set_iga == IGA1) { + switch (i) { + case H_TOTAL_INDEX: + reg_value = + IGA1_HOR_TOTAL_FORMULA(device_timing. + hor_total); + viafb_load_reg_num = + iga1_crtc_reg.hor_total.reg_num; + reg = iga1_crtc_reg.hor_total.reg; + break; + case H_ADDR_INDEX: + reg_value = + IGA1_HOR_ADDR_FORMULA(device_timing. + hor_addr); + viafb_load_reg_num = + iga1_crtc_reg.hor_addr.reg_num; + reg = iga1_crtc_reg.hor_addr.reg; + break; + case H_BLANK_START_INDEX: + reg_value = + IGA1_HOR_BLANK_START_FORMULA + (device_timing.hor_blank_start); + viafb_load_reg_num = + iga1_crtc_reg.hor_blank_start.reg_num; + reg = iga1_crtc_reg.hor_blank_start.reg; + break; + case H_BLANK_END_INDEX: + reg_value = + IGA1_HOR_BLANK_END_FORMULA + (device_timing.hor_blank_start, + device_timing.hor_blank_end); + viafb_load_reg_num = + iga1_crtc_reg.hor_blank_end.reg_num; + reg = iga1_crtc_reg.hor_blank_end.reg; + break; + case H_SYNC_START_INDEX: + reg_value = + IGA1_HOR_SYNC_START_FORMULA + (device_timing.hor_sync_start); + viafb_load_reg_num = + iga1_crtc_reg.hor_sync_start.reg_num; + reg = iga1_crtc_reg.hor_sync_start.reg; + break; + case H_SYNC_END_INDEX: + reg_value = + IGA1_HOR_SYNC_END_FORMULA + (device_timing.hor_sync_start, + device_timing.hor_sync_end); + viafb_load_reg_num = + iga1_crtc_reg.hor_sync_end.reg_num; + reg = iga1_crtc_reg.hor_sync_end.reg; + break; + case V_TOTAL_INDEX: + reg_value = + IGA1_VER_TOTAL_FORMULA(device_timing. + ver_total); + viafb_load_reg_num = + iga1_crtc_reg.ver_total.reg_num; + reg = iga1_crtc_reg.ver_total.reg; + break; + case V_ADDR_INDEX: + reg_value = + IGA1_VER_ADDR_FORMULA(device_timing. + ver_addr); + viafb_load_reg_num = + iga1_crtc_reg.ver_addr.reg_num; + reg = iga1_crtc_reg.ver_addr.reg; + break; + case V_BLANK_START_INDEX: + reg_value = + IGA1_VER_BLANK_START_FORMULA + (device_timing.ver_blank_start); + viafb_load_reg_num = + iga1_crtc_reg.ver_blank_start.reg_num; + reg = iga1_crtc_reg.ver_blank_start.reg; + break; + case V_BLANK_END_INDEX: + reg_value = + IGA1_VER_BLANK_END_FORMULA + (device_timing.ver_blank_start, + device_timing.ver_blank_end); + viafb_load_reg_num = + iga1_crtc_reg.ver_blank_end.reg_num; + reg = iga1_crtc_reg.ver_blank_end.reg; + break; + case V_SYNC_START_INDEX: + reg_value = + IGA1_VER_SYNC_START_FORMULA + (device_timing.ver_sync_start); + viafb_load_reg_num = + iga1_crtc_reg.ver_sync_start.reg_num; + reg = iga1_crtc_reg.ver_sync_start.reg; + break; + case V_SYNC_END_INDEX: + reg_value = + IGA1_VER_SYNC_END_FORMULA + (device_timing.ver_sync_start, + device_timing.ver_sync_end); + viafb_load_reg_num = + iga1_crtc_reg.ver_sync_end.reg_num; + reg = iga1_crtc_reg.ver_sync_end.reg; + break; + + } + } + + if (set_iga == IGA2) { + switch (i) { + case H_TOTAL_INDEX: + reg_value = + IGA2_HOR_TOTAL_FORMULA(device_timing. + hor_total); + viafb_load_reg_num = + iga2_crtc_reg.hor_total.reg_num; + reg = iga2_crtc_reg.hor_total.reg; + break; + case H_ADDR_INDEX: + reg_value = + IGA2_HOR_ADDR_FORMULA(device_timing. + hor_addr); + viafb_load_reg_num = + iga2_crtc_reg.hor_addr.reg_num; + reg = iga2_crtc_reg.hor_addr.reg; + break; + case H_BLANK_START_INDEX: + reg_value = + IGA2_HOR_BLANK_START_FORMULA + (device_timing.hor_blank_start); + viafb_load_reg_num = + iga2_crtc_reg.hor_blank_start.reg_num; + reg = iga2_crtc_reg.hor_blank_start.reg; + break; + case H_BLANK_END_INDEX: + reg_value = + IGA2_HOR_BLANK_END_FORMULA + (device_timing.hor_blank_start, + device_timing.hor_blank_end); + viafb_load_reg_num = + iga2_crtc_reg.hor_blank_end.reg_num; + reg = iga2_crtc_reg.hor_blank_end.reg; + break; + case H_SYNC_START_INDEX: + reg_value = + IGA2_HOR_SYNC_START_FORMULA + (device_timing.hor_sync_start); + if (UNICHROME_CN700 <= + viaparinfo->chip_info->gfx_chip_name) + viafb_load_reg_num = + iga2_crtc_reg.hor_sync_start. + reg_num; + else + viafb_load_reg_num = 3; + reg = iga2_crtc_reg.hor_sync_start.reg; + break; + case H_SYNC_END_INDEX: + reg_value = + IGA2_HOR_SYNC_END_FORMULA + (device_timing.hor_sync_start, + device_timing.hor_sync_end); + viafb_load_reg_num = + iga2_crtc_reg.hor_sync_end.reg_num; + reg = iga2_crtc_reg.hor_sync_end.reg; + break; + case V_TOTAL_INDEX: + reg_value = + IGA2_VER_TOTAL_FORMULA(device_timing. + ver_total); + viafb_load_reg_num = + iga2_crtc_reg.ver_total.reg_num; + reg = iga2_crtc_reg.ver_total.reg; + break; + case V_ADDR_INDEX: + reg_value = + IGA2_VER_ADDR_FORMULA(device_timing. + ver_addr); + viafb_load_reg_num = + iga2_crtc_reg.ver_addr.reg_num; + reg = iga2_crtc_reg.ver_addr.reg; + break; + case V_BLANK_START_INDEX: + reg_value = + IGA2_VER_BLANK_START_FORMULA + (device_timing.ver_blank_start); + viafb_load_reg_num = + iga2_crtc_reg.ver_blank_start.reg_num; + reg = iga2_crtc_reg.ver_blank_start.reg; + break; + case V_BLANK_END_INDEX: + reg_value = + IGA2_VER_BLANK_END_FORMULA + (device_timing.ver_blank_start, + device_timing.ver_blank_end); + viafb_load_reg_num = + iga2_crtc_reg.ver_blank_end.reg_num; + reg = iga2_crtc_reg.ver_blank_end.reg; + break; + case V_SYNC_START_INDEX: + reg_value = + IGA2_VER_SYNC_START_FORMULA + (device_timing.ver_sync_start); + viafb_load_reg_num = + iga2_crtc_reg.ver_sync_start.reg_num; + reg = iga2_crtc_reg.ver_sync_start.reg; + break; + case V_SYNC_END_INDEX: + reg_value = + IGA2_VER_SYNC_END_FORMULA + (device_timing.ver_sync_start, + device_timing.ver_sync_end); + viafb_load_reg_num = + iga2_crtc_reg.ver_sync_end.reg_num; + reg = iga2_crtc_reg.ver_sync_end.reg; + break; + + } + } + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); + } + + viafb_lock_crt(); +} + +void viafb_set_color_depth(int bpp_byte, int set_iga) +{ + if (set_iga == IGA1) { + switch (bpp_byte) { + case MODE_8BPP: + viafb_write_reg_mask(SR15, VIASR, 0x22, 0x7E); + break; + case MODE_16BPP: + viafb_write_reg_mask(SR15, VIASR, 0xB6, 0xFE); + break; + case MODE_32BPP: + viafb_write_reg_mask(SR15, VIASR, 0xAE, 0xFE); + break; + } + } else { + switch (bpp_byte) { + case MODE_8BPP: + viafb_write_reg_mask(CR67, VIACR, 0x00, BIT6 + BIT7); + break; + case MODE_16BPP: + viafb_write_reg_mask(CR67, VIACR, 0x40, BIT6 + BIT7); + break; + case MODE_32BPP: + viafb_write_reg_mask(CR67, VIACR, 0xC0, BIT6 + BIT7); + break; + } + } +} + +void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, + int mode_index, int bpp_byte, int set_iga) +{ + struct VideoModeTable *video_mode; + struct display_timing crt_reg; + int i; + int index = 0; + int h_addr, v_addr; + u32 pll_D_N; + + video_mode = &CLE266Modes[search_mode_setting(mode_index)]; + + for (i = 0; i < video_mode->mode_array; i++) { + index = i; + + if (crt_table[i].refresh_rate == viaparinfo-> + crt_setting_info->refresh_rate) + break; + } + + crt_reg = crt_table[index].crtc; + + /* Mode 640x480 has border, but LCD/DFP didn't have border. */ + /* So we would delete border. */ + if ((viafb_LCD_ON | viafb_DVI_ON) && (mode_index == VIA_RES_640X480) + && (viaparinfo->crt_setting_info->refresh_rate == 60)) { + /* The border is 8 pixels. */ + crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8; + + /* Blanking time should add left and right borders. */ + crt_reg.hor_blank_end = crt_reg.hor_blank_end + 16; + } + + h_addr = crt_reg.hor_addr; + v_addr = crt_reg.ver_addr; + + /* update polarity for CRT timing */ + if (crt_table[index].h_sync_polarity == NEGATIVE) { + if (crt_table[index].v_sync_polarity == NEGATIVE) + outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | + (BIT6 + BIT7), VIAWMisc); + else + outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT6), + VIAWMisc); + } else { + if (crt_table[index].v_sync_polarity == NEGATIVE) + outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT7), + VIAWMisc); + else + outb((inb(VIARMisc) & (~(BIT6 + BIT7))), VIAWMisc); + } + + if (set_iga == IGA1) { + viafb_unlock_crt(); + viafb_write_reg(CR09, VIACR, 0x00); /*initial CR09=0 */ + viafb_write_reg_mask(CR11, VIACR, 0x00, BIT4 + BIT5 + BIT6); + viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); + } + + switch (set_iga) { + case IGA1: + viafb_load_crtc_timing(crt_reg, IGA1); + break; + case IGA2: + viafb_load_crtc_timing(crt_reg, IGA2); + break; + } + + load_fix_bit_crtc_reg(); + viafb_lock_crt(); + viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); + viafb_load_offset_reg(h_addr, bpp_byte, set_iga); + viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga); + + /* load FIFO */ + if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) + && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400)) + viafb_load_FIFO_reg(set_iga, h_addr, v_addr); + + /* load SR Register About Memory and Color part */ + viafb_set_color_depth(bpp_byte, set_iga); + + pll_D_N = viafb_get_clk_value(crt_table[index].clk); + DEBUG_MSG(KERN_INFO "PLL=%x", pll_D_N); + viafb_set_vclock(pll_D_N, set_iga); + +} + +void viafb_init_chip_info(void) +{ + init_gfx_chip_info(); + init_tmds_chip_info(); + init_lvds_chip_info(); + + viaparinfo->crt_setting_info->iga_path = IGA1; + viaparinfo->crt_setting_info->refresh_rate = viafb_refresh; + + /*Set IGA path for each device */ + viafb_set_iga_path(); + + viaparinfo->lvds_setting_info->display_method = viafb_lcd_dsp_method; + viaparinfo->lvds_setting_info->get_lcd_size_method = + GET_LCD_SIZE_BY_USER_SETTING; + viaparinfo->lvds_setting_info->lcd_mode = viafb_lcd_mode; + viaparinfo->lvds_setting_info2->display_method = + viaparinfo->lvds_setting_info->display_method; + viaparinfo->lvds_setting_info2->lcd_mode = + viaparinfo->lvds_setting_info->lcd_mode; +} + +void viafb_update_device_setting(int hres, int vres, + int bpp, int vmode_refresh, int flag) +{ + if (flag == 0) { + viaparinfo->crt_setting_info->h_active = hres; + viaparinfo->crt_setting_info->v_active = vres; + viaparinfo->crt_setting_info->bpp = bpp; + viaparinfo->crt_setting_info->refresh_rate = + vmode_refresh; + + viaparinfo->tmds_setting_info->h_active = hres; + viaparinfo->tmds_setting_info->v_active = vres; + viaparinfo->tmds_setting_info->bpp = bpp; + viaparinfo->tmds_setting_info->refresh_rate = + vmode_refresh; + + viaparinfo->lvds_setting_info->h_active = hres; + viaparinfo->lvds_setting_info->v_active = vres; + viaparinfo->lvds_setting_info->bpp = bpp; + viaparinfo->lvds_setting_info->refresh_rate = + vmode_refresh; + viaparinfo->lvds_setting_info2->h_active = hres; + viaparinfo->lvds_setting_info2->v_active = vres; + viaparinfo->lvds_setting_info2->bpp = bpp; + viaparinfo->lvds_setting_info2->refresh_rate = + vmode_refresh; + } else { + + if (viaparinfo->tmds_setting_info->iga_path == IGA2) { + viaparinfo->tmds_setting_info->h_active = hres; + viaparinfo->tmds_setting_info->v_active = vres; + viaparinfo->tmds_setting_info->bpp = bpp; + viaparinfo->tmds_setting_info->refresh_rate = + vmode_refresh; + } + + if (viaparinfo->lvds_setting_info->iga_path == IGA2) { + viaparinfo->lvds_setting_info->h_active = hres; + viaparinfo->lvds_setting_info->v_active = vres; + viaparinfo->lvds_setting_info->bpp = bpp; + viaparinfo->lvds_setting_info->refresh_rate = + vmode_refresh; + } + if (IGA2 == viaparinfo->lvds_setting_info2->iga_path) { + viaparinfo->lvds_setting_info2->h_active = hres; + viaparinfo->lvds_setting_info2->v_active = vres; + viaparinfo->lvds_setting_info2->bpp = bpp; + viaparinfo->lvds_setting_info2->refresh_rate = + vmode_refresh; + } + } +} + +static void init_gfx_chip_info(void) +{ + struct pci_dev *pdev = NULL; + u32 i; + u8 tmp; + + /* Indentify GFX Chip Name */ + for (i = 0; pciidlist[i].vendor != 0; i++) { + pdev = pci_get_device(pciidlist[i].vendor, + pciidlist[i].device, 0); + if (pdev) + break; + } + + if (!pciidlist[i].vendor) + return ; + + viaparinfo->chip_info->gfx_chip_name = pciidlist[i].chip_index; + + /* Check revision of CLE266 Chip */ + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { + /* CR4F only define in CLE266.CX chip */ + tmp = viafb_read_reg(VIACR, CR4F); + viafb_write_reg(CR4F, VIACR, 0x55); + if (viafb_read_reg(VIACR, CR4F) != 0x55) + viaparinfo->chip_info->gfx_chip_revision = + CLE266_REVISION_AX; + else + viaparinfo->chip_info->gfx_chip_revision = + CLE266_REVISION_CX; + /* restore orignal CR4F value */ + viafb_write_reg(CR4F, VIACR, tmp); + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { + tmp = viafb_read_reg(VIASR, SR43); + DEBUG_MSG(KERN_INFO "SR43:%X\n", tmp); + if (tmp & 0x02) { + viaparinfo->chip_info->gfx_chip_revision = + CX700_REVISION_700M2; + } else if (tmp & 0x40) { + viaparinfo->chip_info->gfx_chip_revision = + CX700_REVISION_700M; + } else { + viaparinfo->chip_info->gfx_chip_revision = + CX700_REVISION_700; + } + } + + pci_dev_put(pdev); +} + +static void init_tmds_chip_info(void) +{ + viafb_tmds_trasmitter_identify(); + + if (INTERFACE_NONE == viaparinfo->chip_info->tmds_chip_info. + output_interface) { + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CX700: + { + /* we should check support by hardware layout.*/ + if ((viafb_display_hardware_layout == + HW_LAYOUT_DVI_ONLY) + || (viafb_display_hardware_layout == + HW_LAYOUT_LCD_DVI)) { + viaparinfo->chip_info->tmds_chip_info. + output_interface = INTERFACE_TMDS; + } else { + viaparinfo->chip_info->tmds_chip_info. + output_interface = + INTERFACE_NONE; + } + break; + } + case UNICHROME_K8M890: + case UNICHROME_P4M900: + case UNICHROME_P4M890: + /* TMDS on PCIE, we set DFPLOW as default. */ + viaparinfo->chip_info->tmds_chip_info.output_interface = + INTERFACE_DFP_LOW; + break; + default: + { + /* set DVP1 default for DVI */ + viaparinfo->chip_info->tmds_chip_info + .output_interface = INTERFACE_DVP1; + } + } + } + + DEBUG_MSG(KERN_INFO "TMDS Chip = %d\n", + viaparinfo->chip_info->tmds_chip_info.tmds_chip_name); + viaparinfo->tmds_setting_info->get_dvi_size_method = + GET_DVI_SIZE_BY_VGA_BIOS; + viafb_init_dvi_size(); +} + +static void init_lvds_chip_info(void) +{ + if (viafb_lcd_panel_id > LCD_PANEL_ID_MAXIMUM) + viaparinfo->lvds_setting_info->get_lcd_size_method = + GET_LCD_SIZE_BY_VGA_BIOS; + else + viaparinfo->lvds_setting_info->get_lcd_size_method = + GET_LCD_SIZE_BY_USER_SETTING; + + viafb_lvds_trasmitter_identify(); + viafb_init_lcd_size(); + viafb_init_lvds_output_interface(&viaparinfo->chip_info->lvds_chip_info, + viaparinfo->lvds_setting_info); + if (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { + viafb_init_lvds_output_interface(&viaparinfo->chip_info-> + lvds_chip_info2, viaparinfo->lvds_setting_info2); + } + /*If CX700,two singel LCD, we need to reassign + LCD interface to different LVDS port */ + if ((UNICHROME_CX700 == viaparinfo->chip_info->gfx_chip_name) + && (HW_LAYOUT_LCD1_LCD2 == viafb_display_hardware_layout)) { + if ((INTEGRATED_LVDS == viaparinfo->chip_info->lvds_chip_info. + lvds_chip_name) && (INTEGRATED_LVDS == + viaparinfo->chip_info-> + lvds_chip_info2.lvds_chip_name)) { + viaparinfo->chip_info->lvds_chip_info.output_interface = + INTERFACE_LVDS0; + viaparinfo->chip_info->lvds_chip_info2. + output_interface = + INTERFACE_LVDS1; + } + } + + DEBUG_MSG(KERN_INFO "LVDS Chip = %d\n", + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name); + DEBUG_MSG(KERN_INFO "LVDS1 output_interface = %d\n", + viaparinfo->chip_info->lvds_chip_info.output_interface); + DEBUG_MSG(KERN_INFO "LVDS2 output_interface = %d\n", + viaparinfo->chip_info->lvds_chip_info.output_interface); +} + +void viafb_init_dac(int set_iga) +{ + int i; + u8 tmp; + + if (set_iga == IGA1) { + /* access Primary Display's LUT */ + viafb_write_reg_mask(SR1A, VIASR, 0x00, BIT0); + /* turn off LCK */ + viafb_write_reg_mask(SR1B, VIASR, 0x00, BIT7 + BIT6); + for (i = 0; i < 256; i++) { + write_dac_reg(i, palLUT_table[i].red, + palLUT_table[i].green, + palLUT_table[i].blue); + } + /* turn on LCK */ + viafb_write_reg_mask(SR1B, VIASR, 0xC0, BIT7 + BIT6); + } else { + tmp = viafb_read_reg(VIACR, CR6A); + /* access Secondary Display's LUT */ + viafb_write_reg_mask(CR6A, VIACR, 0x40, BIT6); + viafb_write_reg_mask(SR1A, VIASR, 0x01, BIT0); + for (i = 0; i < 256; i++) { + write_dac_reg(i, palLUT_table[i].red, + palLUT_table[i].green, + palLUT_table[i].blue); + } + /* set IGA1 DAC for default */ + viafb_write_reg_mask(SR1A, VIASR, 0x00, BIT0); + viafb_write_reg(CR6A, VIACR, tmp); + } +} + +static void device_screen_off(void) +{ + /* turn off CRT screen (IGA1) */ + viafb_write_reg_mask(SR01, VIASR, 0x20, BIT5); +} + +static void device_screen_on(void) +{ + /* turn on CRT screen (IGA1) */ + viafb_write_reg_mask(SR01, VIASR, 0x00, BIT5); +} + +static void set_display_channel(void) +{ + /*If viafb_LCD2_ON, on cx700, internal lvds's information + is keeped on lvds_setting_info2 */ + if (viafb_LCD2_ON && + viaparinfo->lvds_setting_info2->device_lcd_dualedge) { + /* For dual channel LCD: */ + /* Set to Dual LVDS channel. */ + viafb_write_reg_mask(CRD2, VIACR, 0x20, BIT4 + BIT5); + } else if (viafb_LCD_ON && viafb_DVI_ON) { + /* For LCD+DFP: */ + /* Set to LVDS1 + TMDS channel. */ + viafb_write_reg_mask(CRD2, VIACR, 0x10, BIT4 + BIT5); + } else if (viafb_DVI_ON) { + /* Set to single TMDS channel. */ + viafb_write_reg_mask(CRD2, VIACR, 0x30, BIT4 + BIT5); + } else if (viafb_LCD_ON) { + if (viaparinfo->lvds_setting_info->device_lcd_dualedge) { + /* For dual channel LCD: */ + /* Set to Dual LVDS channel. */ + viafb_write_reg_mask(CRD2, VIACR, 0x20, BIT4 + BIT5); + } else { + /* Set to LVDS0 + LVDS1 channel. */ + viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT4 + BIT5); + } + } +} + +int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp, + int vmode_index1, int hor_res1, int ver_res1, int video_bpp1) +{ + int i, j; + int port; + u8 value, index, mask; + struct VideoModeTable *vmode_tbl; + struct crt_mode_table *crt_timing; + struct VideoModeTable *vmode_tbl1 = NULL; + struct crt_mode_table *crt_timing1 = NULL; + + DEBUG_MSG(KERN_INFO "Set Mode!!\n"); + DEBUG_MSG(KERN_INFO + "vmode_index=%d hor_res=%d ver_res=%d video_bpp=%d\n", + vmode_index, hor_res, ver_res, video_bpp); + + device_screen_off(); + vmode_tbl = &CLE266Modes[search_mode_setting(vmode_index)]; + crt_timing = vmode_tbl->crtc; + + if (viafb_SAMM_ON == 1) { + vmode_tbl1 = &CLE266Modes[search_mode_setting(vmode_index1)]; + crt_timing1 = vmode_tbl1->crtc; + } + + inb(VIAStatus); + outb(0x00, VIAAR); + + /* Write Common Setting for Video Mode */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + viafb_write_regx(CLE266_ModeXregs, NUM_TOTAL_CLE266_ModeXregs); + break; + + case UNICHROME_K400: + viafb_write_regx(KM400_ModeXregs, NUM_TOTAL_KM400_ModeXregs); + break; + + case UNICHROME_K800: + case UNICHROME_PM800: + viafb_write_regx(CN400_ModeXregs, NUM_TOTAL_CN400_ModeXregs); + break; + + case UNICHROME_CN700: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + case UNICHROME_P4M900: + viafb_write_regx(CN700_ModeXregs, NUM_TOTAL_CN700_ModeXregs); + break; + + case UNICHROME_CX700: + viafb_write_regx(CX700_ModeXregs, NUM_TOTAL_CX700_ModeXregs); + + case UNICHROME_VX800: + viafb_write_regx(VX800_ModeXregs, NUM_TOTAL_VX800_ModeXregs); + + break; + } + + device_off(); + + /* Fill VPIT Parameters */ + /* Write Misc Register */ + outb(VPIT.Misc, VIAWMisc); + + /* Write Sequencer */ + for (i = 1; i <= StdSR; i++) { + outb(i, VIASR); + outb(VPIT.SR[i - 1], VIASR + 1); + } + + viafb_set_start_addr(); + viafb_set_iga_path(); + + /* Write CRTC */ + viafb_fill_crtc_timing(crt_timing, vmode_index, video_bpp / 8, IGA1); + + /* Write Graphic Controller */ + for (i = 0; i < StdGR; i++) { + outb(i, VIAGR); + outb(VPIT.GR[i], VIAGR + 1); + } + + /* Write Attribute Controller */ + for (i = 0; i < StdAR; i++) { + inb(VIAStatus); + outb(i, VIAAR); + outb(VPIT.AR[i], VIAAR); + } + + inb(VIAStatus); + outb(0x20, VIAAR); + + /* Update Patch Register */ + + if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + || (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)) { + for (i = 0; i < NUM_TOTAL_PATCH_MODE; i++) { + if (res_patch_table[i].mode_index == vmode_index) { + for (j = 0; + j < res_patch_table[i].table_length; j++) { + index = + res_patch_table[i]. + io_reg_table[j].index; + port = + res_patch_table[i]. + io_reg_table[j].port; + value = + res_patch_table[i]. + io_reg_table[j].value; + mask = + res_patch_table[i]. + io_reg_table[j].mask; + viafb_write_reg_mask(index, port, value, + mask); + } + } + } + } + + if (viafb_SAMM_ON == 1) { + if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + || (viaparinfo->chip_info->gfx_chip_name == + UNICHROME_K400)) { + for (i = 0; i < NUM_TOTAL_PATCH_MODE; i++) { + if (res_patch_table[i].mode_index == + vmode_index1) { + for (j = 0; + j < + res_patch_table[i]. + table_length; j++) { + index = + res_patch_table[i]. + io_reg_table[j].index; + port = + res_patch_table[i]. + io_reg_table[j].port; + value = + res_patch_table[i]. + io_reg_table[j].value; + mask = + res_patch_table[i]. + io_reg_table[j].mask; + viafb_write_reg_mask(index, + port, value, mask); + } + } + } + } + } + + /* Update Refresh Rate Setting */ + + /* Clear On Screen */ + + /* CRT set mode */ + if (viafb_CRT_ON) { + if (viafb_SAMM_ON && (viaparinfo->crt_setting_info->iga_path == + IGA2)) { + viafb_fill_crtc_timing(crt_timing1, vmode_index1, + video_bpp1 / 8, + viaparinfo->crt_setting_info->iga_path); + } else { + viafb_fill_crtc_timing(crt_timing, vmode_index, + video_bpp / 8, + viaparinfo->crt_setting_info->iga_path); + } + + set_crt_output_path(viaparinfo->crt_setting_info->iga_path); + + /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode + to 8 alignment (1368),there is several pixels (2 pixels) + on right side of screen. */ + if (hor_res % 8) { + viafb_unlock_crt(); + viafb_write_reg(CR02, VIACR, + viafb_read_reg(VIACR, CR02) - 1); + viafb_lock_crt(); + } + } + + if (viafb_DVI_ON) { + if (viafb_SAMM_ON && + (viaparinfo->tmds_setting_info->iga_path == IGA2)) { + viafb_dvi_set_mode(viafb_get_mode_index + (viaparinfo->tmds_setting_info->h_active, + viaparinfo->tmds_setting_info-> + v_active, 1), + video_bpp1, viaparinfo-> + tmds_setting_info->iga_path); + } else { + viafb_dvi_set_mode(viafb_get_mode_index + (viaparinfo->tmds_setting_info->h_active, + viaparinfo-> + tmds_setting_info->v_active, 0), + video_bpp, viaparinfo-> + tmds_setting_info->iga_path); + } + } + + if (viafb_LCD_ON) { + if (viafb_SAMM_ON && + (viaparinfo->lvds_setting_info->iga_path == IGA2)) { + viaparinfo->lvds_setting_info->bpp = video_bpp1; + viafb_lcd_set_mode(crt_timing1, viaparinfo-> + lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); + } else { + /* IGA1 doesn't have LCD scaling, so set it center. */ + if (viaparinfo->lvds_setting_info->iga_path == IGA1) { + viaparinfo->lvds_setting_info->display_method = + LCD_CENTERING; + } + viaparinfo->lvds_setting_info->bpp = video_bpp; + viafb_lcd_set_mode(crt_timing, viaparinfo-> + lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); + } + } + if (viafb_LCD2_ON) { + if (viafb_SAMM_ON && + (viaparinfo->lvds_setting_info2->iga_path == IGA2)) { + viaparinfo->lvds_setting_info2->bpp = video_bpp1; + viafb_lcd_set_mode(crt_timing1, viaparinfo-> + lvds_setting_info2, + &viaparinfo->chip_info->lvds_chip_info2); + } else { + /* IGA1 doesn't have LCD scaling, so set it center. */ + if (viaparinfo->lvds_setting_info2->iga_path == IGA1) { + viaparinfo->lvds_setting_info2->display_method = + LCD_CENTERING; + } + viaparinfo->lvds_setting_info2->bpp = video_bpp; + viafb_lcd_set_mode(crt_timing, viaparinfo-> + lvds_setting_info2, + &viaparinfo->chip_info->lvds_chip_info2); + } + } + + if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) + && (viafb_LCD_ON || viafb_DVI_ON)) + set_display_channel(); + + /* If set mode normally, save resolution information for hot-plug . */ + if (!viafb_hotplug) { + viafb_hotplug_Xres = hor_res; + viafb_hotplug_Yres = ver_res; + viafb_hotplug_bpp = video_bpp; + viafb_hotplug_refresh = viafb_refresh; + + if (viafb_DVI_ON) + viafb_DeviceStatus = DVI_Device; + else + viafb_DeviceStatus = CRT_Device; + } + device_on(); + + if (viafb_SAMM_ON == 1) + viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7); + + device_screen_on(); + return 1; +} + +int viafb_get_pixclock(int hres, int vres, int vmode_refresh) +{ + int i; + + for (i = 0; i < NUM_TOTAL_RES_MAP_REFRESH; i++) { + if ((hres == res_map_refresh_tbl[i].hres) + && (vres == res_map_refresh_tbl[i].vres) + && (vmode_refresh == res_map_refresh_tbl[i].vmode_refresh)) + return res_map_refresh_tbl[i].pixclock; + } + return RES_640X480_60HZ_PIXCLOCK; + +} + +int viafb_get_refresh(int hres, int vres, u32 long_refresh) +{ +#define REFRESH_TOLERANCE 3 + int i, nearest = -1, diff = REFRESH_TOLERANCE; + for (i = 0; i < NUM_TOTAL_RES_MAP_REFRESH; i++) { + if ((hres == res_map_refresh_tbl[i].hres) + && (vres == res_map_refresh_tbl[i].vres) + && (diff > (abs(long_refresh - + res_map_refresh_tbl[i].vmode_refresh)))) { + diff = abs(long_refresh - res_map_refresh_tbl[i]. + vmode_refresh); + nearest = i; + } + } +#undef REFRESH_TOLERANCE + if (nearest > 0) + return res_map_refresh_tbl[nearest].vmode_refresh; + return 60; +} + +static void device_off(void) +{ + viafb_crt_disable(); + viafb_dvi_disable(); + viafb_lcd_disable(); +} + +static void device_on(void) +{ + if (viafb_CRT_ON == 1) + viafb_crt_enable(); + if (viafb_DVI_ON == 1) + viafb_dvi_enable(); + if (viafb_LCD_ON == 1) + viafb_lcd_enable(); +} + +void viafb_crt_disable(void) +{ + viafb_write_reg_mask(CR36, VIACR, BIT5 + BIT4, BIT5 + BIT4); +} + +void viafb_crt_enable(void) +{ + viafb_write_reg_mask(CR36, VIACR, 0x0, BIT5 + BIT4); +} + +void viafb_get_mmio_info(unsigned long *mmio_base, + unsigned long *mmio_len) +{ + struct pci_dev *pdev = NULL; + u32 vendor, device; + u32 i; + + for (i = 0; pciidlist[i].vendor != 0; i++) + if (viaparinfo->chip_info->gfx_chip_name == + pciidlist[i].chip_index) + break; + + if (!pciidlist[i].vendor) + return ; + + vendor = pciidlist[i].vendor; + device = pciidlist[i].device; + + pdev = pci_get_device(vendor, device, NULL); + + if (!pdev) { + *mmio_base = 0; + *mmio_len = 0; + return ; + } + + *mmio_base = pci_resource_start(pdev, 1); + *mmio_len = pci_resource_len(pdev, 1); + + pci_dev_put(pdev); +} + +static void enable_second_display_channel(void) +{ + /* to enable second display channel. */ + viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT6); + viafb_write_reg_mask(CR6A, VIACR, BIT7, BIT7); + viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6); +} + +static void disable_second_display_channel(void) +{ + /* to disable second display channel. */ + viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT6); + viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT7); + viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6); +} + +void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len) +{ + struct pci_dev *pdev = NULL; + u32 vendor, device; + u32 i; + + for (i = 0; pciidlist[i].vendor != 0; i++) + if (viaparinfo->chip_info->gfx_chip_name == + pciidlist[i].chip_index) + break; + + if (!pciidlist[i].vendor) + return ; + + vendor = pciidlist[i].vendor; + device = pciidlist[i].device; + + pdev = pci_get_device(vendor, device, NULL); + + if (!pdev) { + *fb_base = viafb_read_reg(VIASR, SR30) << 24; + *fb_len = viafb_get_memsize(); + DEBUG_MSG(KERN_INFO "Get FB info from SR30!\n"); + DEBUG_MSG(KERN_INFO "fb_base = %08x\n", *fb_base); + DEBUG_MSG(KERN_INFO "fb_len = %08x\n", *fb_len); + return ; + } + + *fb_base = (unsigned int)pci_resource_start(pdev, 0); + *fb_len = get_fb_size_from_pci(); + DEBUG_MSG(KERN_INFO "Get FB info from PCI system!\n"); + DEBUG_MSG(KERN_INFO "fb_base = %08x\n", *fb_base); + DEBUG_MSG(KERN_INFO "fb_len = %08x\n", *fb_len); + + pci_dev_put(pdev); +} + +static int get_fb_size_from_pci(void) +{ + unsigned long configid, deviceid, FBSize = 0; + int VideoMemSize; + int DeviceFound = false; + + for (configid = 0x80000000; configid < 0x80010800; configid += 0x100) { + outl(configid, (unsigned long)0xCF8); + deviceid = (inl((unsigned long)0xCFC) >> 16) & 0xffff; + + switch (deviceid) { + case CLE266: + case KM400: + outl(configid + 0xE0, (unsigned long)0xCF8); + FBSize = inl((unsigned long)0xCFC); + DeviceFound = true; /* Found device id */ + break; + + case CN400_FUNCTION3: + case CN700_FUNCTION3: + case CX700_FUNCTION3: + case KM800_FUNCTION3: + case KM890_FUNCTION3: + case P4M890_FUNCTION3: + case P4M900_FUNCTION3: + case VX800_FUNCTION3: + /*case CN750_FUNCTION3: */ + outl(configid + 0xA0, (unsigned long)0xCF8); + FBSize = inl((unsigned long)0xCFC); + DeviceFound = true; /* Found device id */ + break; + + default: + break; + } + + if (DeviceFound) + break; + } + + DEBUG_MSG(KERN_INFO "Device ID = %lx\n", deviceid); + + FBSize = FBSize & 0x00007000; + DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize); + + if (viaparinfo->chip_info->gfx_chip_name < UNICHROME_CX700) { + switch (FBSize) { + case 0x00004000: + VideoMemSize = (16 << 20); /*16M */ + break; + + case 0x00005000: + VideoMemSize = (32 << 20); /*32M */ + break; + + case 0x00006000: + VideoMemSize = (64 << 20); /*64M */ + break; + + default: + VideoMemSize = (32 << 20); /*32M */ + break; + } + } else { + switch (FBSize) { + case 0x00001000: + VideoMemSize = (8 << 20); /*8M */ + break; + + case 0x00002000: + VideoMemSize = (16 << 20); /*16M */ + break; + + case 0x00003000: + VideoMemSize = (32 << 20); /*32M */ + break; + + case 0x00004000: + VideoMemSize = (64 << 20); /*64M */ + break; + + case 0x00005000: + VideoMemSize = (128 << 20); /*128M */ + break; + + case 0x00006000: + VideoMemSize = (256 << 20); /*256M */ + break; + + default: + VideoMemSize = (32 << 20); /*32M */ + break; + } + } + + return VideoMemSize; +} + +void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ + *p_gfx_dpa_setting) +{ + switch (output_interface) { + case INTERFACE_DVP0: + { + /* DVP0 Clock Polarity and Adjust: */ + viafb_write_reg_mask(CR96, VIACR, + p_gfx_dpa_setting->DVP0, 0x0F); + + /* DVP0 Clock and Data Pads Driving: */ + viafb_write_reg_mask(SR1E, VIASR, + p_gfx_dpa_setting->DVP0ClockDri_S, BIT2); + viafb_write_reg_mask(SR2A, VIASR, + p_gfx_dpa_setting->DVP0ClockDri_S1, + BIT4); + viafb_write_reg_mask(SR1B, VIASR, + p_gfx_dpa_setting->DVP0DataDri_S, BIT1); + viafb_write_reg_mask(SR2A, VIASR, + p_gfx_dpa_setting->DVP0DataDri_S1, BIT5); + break; + } + + case INTERFACE_DVP1: + { + /* DVP1 Clock Polarity and Adjust: */ + viafb_write_reg_mask(CR9B, VIACR, + p_gfx_dpa_setting->DVP1, 0x0F); + + /* DVP1 Clock and Data Pads Driving: */ + viafb_write_reg_mask(SR65, VIASR, + p_gfx_dpa_setting->DVP1Driving, 0x0F); + break; + } + + case INTERFACE_DFP_HIGH: + { + viafb_write_reg_mask(CR97, VIACR, + p_gfx_dpa_setting->DFPHigh, 0x0F); + break; + } + + case INTERFACE_DFP_LOW: + { + viafb_write_reg_mask(CR99, VIACR, + p_gfx_dpa_setting->DFPLow, 0x0F); + break; + } + + case INTERFACE_DFP: + { + viafb_write_reg_mask(CR97, VIACR, + p_gfx_dpa_setting->DFPHigh, 0x0F); + viafb_write_reg_mask(CR99, VIACR, + p_gfx_dpa_setting->DFPLow, 0x0F); + break; + } + } +} + +void viafb_memory_pitch_patch(struct fb_info *info) +{ + if (info->var.xres != info->var.xres_virtual) { + viafb_load_offset_reg(info->var.xres_virtual, + info->var.bits_per_pixel >> 3, IGA1); + + if (viafb_SAMM_ON) { + viafb_load_offset_reg(viafb_second_virtual_xres, + viafb_bpp1 >> 3, + IGA2); + } else { + viafb_load_offset_reg(info->var.xres_virtual, + info->var.bits_per_pixel >> 3, IGA2); + } + + } +} + +/*According var's xres, yres fill var's other timing information*/ +void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh, + int mode_index) +{ + struct VideoModeTable *vmode_tbl = NULL; + struct crt_mode_table *crt_timing = NULL; + struct display_timing crt_reg; + int i = 0, index = 0; + vmode_tbl = &CLE266Modes[search_mode_setting(mode_index)]; + crt_timing = vmode_tbl->crtc; + for (i = 0; i < vmode_tbl->mode_array; i++) { + index = i; + if (crt_timing[i].refresh_rate == refresh) + break; + } + + crt_reg = crt_timing[index].crtc; + switch (var->bits_per_pixel) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; + default: + /* never happed, put here to keep consistent */ + break; + } + + var->pixclock = viafb_get_pixclock(var->xres, var->yres, refresh); + var->left_margin = + crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end); + var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr; + var->hsync_len = crt_reg.hor_sync_end; + var->upper_margin = + crt_reg.ver_total - (crt_reg.ver_sync_start + crt_reg.ver_sync_end); + var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr; + var->vsync_len = crt_reg.ver_sync_end; +} diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h new file mode 100644 index 00000000000..6ff38fa8569 --- /dev/null +++ b/drivers/video/via/hw.h @@ -0,0 +1,933 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __HW_H__ +#define __HW_H__ + +#include "global.h" + +/*************************************************** +* Definition IGA1 Design Method of CRTC Registers * +****************************************************/ +#define IGA1_HOR_TOTAL_FORMULA(x) (((x)/8)-5) +#define IGA1_HOR_ADDR_FORMULA(x) (((x)/8)-1) +#define IGA1_HOR_BLANK_START_FORMULA(x) (((x)/8)-1) +#define IGA1_HOR_BLANK_END_FORMULA(x, y) (((x+y)/8)-1) +#define IGA1_HOR_SYNC_START_FORMULA(x) ((x)/8) +#define IGA1_HOR_SYNC_END_FORMULA(x, y) ((x+y)/8) + +#define IGA1_VER_TOTAL_FORMULA(x) ((x)-2) +#define IGA1_VER_ADDR_FORMULA(x) ((x)-1) +#define IGA1_VER_BLANK_START_FORMULA(x) ((x)-1) +#define IGA1_VER_BLANK_END_FORMULA(x, y) ((x+y)-1) +#define IGA1_VER_SYNC_START_FORMULA(x) ((x)-1) +#define IGA1_VER_SYNC_END_FORMULA(x, y) ((x+y)-1) + +/*************************************************** +** Definition IGA2 Design Method of CRTC Registers * +****************************************************/ +#define IGA2_HOR_TOTAL_FORMULA(x) ((x)-1) +#define IGA2_HOR_ADDR_FORMULA(x) ((x)-1) +#define IGA2_HOR_BLANK_START_FORMULA(x) ((x)-1) +#define IGA2_HOR_BLANK_END_FORMULA(x, y) ((x+y)-1) +#define IGA2_HOR_SYNC_START_FORMULA(x) ((x)-1) +#define IGA2_HOR_SYNC_END_FORMULA(x, y) ((x+y)-1) + +#define IGA2_VER_TOTAL_FORMULA(x) ((x)-1) +#define IGA2_VER_ADDR_FORMULA(x) ((x)-1) +#define IGA2_VER_BLANK_START_FORMULA(x) ((x)-1) +#define IGA2_VER_BLANK_END_FORMULA(x, y) ((x+y)-1) +#define IGA2_VER_SYNC_START_FORMULA(x) ((x)-1) +#define IGA2_VER_SYNC_END_FORMULA(x, y) ((x+y)-1) + +/**********************************************************/ +/* Definition IGA2 Design Method of CRTC Shadow Registers */ +/**********************************************************/ +#define IGA2_HOR_TOTAL_SHADOW_FORMULA(x) ((x/8)-5) +#define IGA2_HOR_BLANK_END_SHADOW_FORMULA(x, y) (((x+y)/8)-1) +#define IGA2_VER_TOTAL_SHADOW_FORMULA(x) ((x)-2) +#define IGA2_VER_ADDR_SHADOW_FORMULA(x) ((x)-1) +#define IGA2_VER_BLANK_START_SHADOW_FORMULA(x) ((x)-1) +#define IGA2_VER_BLANK_END_SHADOW_FORMULA(x, y) ((x+y)-1) +#define IGA2_VER_SYNC_START_SHADOW_FORMULA(x) (x) +#define IGA2_VER_SYNC_END_SHADOW_FORMULA(x, y) (x+y) + +/* Define Register Number for IGA1 CRTC Timing */ + +/* location: {CR00,0,7},{CR36,3,3} */ +#define IGA1_HOR_TOTAL_REG_NUM 2 +/* location: {CR01,0,7} */ +#define IGA1_HOR_ADDR_REG_NUM 1 +/* location: {CR02,0,7} */ +#define IGA1_HOR_BLANK_START_REG_NUM 1 +/* location: {CR03,0,4},{CR05,7,7},{CR33,5,5} */ +#define IGA1_HOR_BLANK_END_REG_NUM 3 +/* location: {CR04,0,7},{CR33,4,4} */ +#define IGA1_HOR_SYNC_START_REG_NUM 2 +/* location: {CR05,0,4} */ +#define IGA1_HOR_SYNC_END_REG_NUM 1 +/* location: {CR06,0,7},{CR07,0,0},{CR07,5,5},{CR35,0,0} */ +#define IGA1_VER_TOTAL_REG_NUM 4 +/* location: {CR12,0,7},{CR07,1,1},{CR07,6,6},{CR35,2,2} */ +#define IGA1_VER_ADDR_REG_NUM 4 +/* location: {CR15,0,7},{CR07,3,3},{CR09,5,5},{CR35,3,3} */ +#define IGA1_VER_BLANK_START_REG_NUM 4 +/* location: {CR16,0,7} */ +#define IGA1_VER_BLANK_END_REG_NUM 1 +/* location: {CR10,0,7},{CR07,2,2},{CR07,7,7},{CR35,1,1} */ +#define IGA1_VER_SYNC_START_REG_NUM 4 +/* location: {CR11,0,3} */ +#define IGA1_VER_SYNC_END_REG_NUM 1 + +/* Define Register Number for IGA2 Shadow CRTC Timing */ + +/* location: {CR6D,0,7},{CR71,3,3} */ +#define IGA2_SHADOW_HOR_TOTAL_REG_NUM 2 +/* location: {CR6E,0,7} */ +#define IGA2_SHADOW_HOR_BLANK_END_REG_NUM 1 +/* location: {CR6F,0,7},{CR71,0,2} */ +#define IGA2_SHADOW_VER_TOTAL_REG_NUM 2 +/* location: {CR70,0,7},{CR71,4,6} */ +#define IGA2_SHADOW_VER_ADDR_REG_NUM 2 +/* location: {CR72,0,7},{CR74,4,6} */ +#define IGA2_SHADOW_VER_BLANK_START_REG_NUM 2 +/* location: {CR73,0,7},{CR74,0,2} */ +#define IGA2_SHADOW_VER_BLANK_END_REG_NUM 2 +/* location: {CR75,0,7},{CR76,4,6} */ +#define IGA2_SHADOW_VER_SYNC_START_REG_NUM 2 +/* location: {CR76,0,3} */ +#define IGA2_SHADOW_VER_SYNC_END_REG_NUM 1 + +/* Define Register Number for IGA2 CRTC Timing */ + +/* location: {CR50,0,7},{CR55,0,3} */ +#define IGA2_HOR_TOTAL_REG_NUM 2 +/* location: {CR51,0,7},{CR55,4,6} */ +#define IGA2_HOR_ADDR_REG_NUM 2 +/* location: {CR52,0,7},{CR54,0,2} */ +#define IGA2_HOR_BLANK_START_REG_NUM 2 +/* location: CLE266: {CR53,0,7},{CR54,3,5} => CLE266's CR5D[6] +is reserved, so it may have problem to set 1600x1200 on IGA2. */ +/* Others: {CR53,0,7},{CR54,3,5},{CR5D,6,6} */ +#define IGA2_HOR_BLANK_END_REG_NUM 3 +/* location: {CR56,0,7},{CR54,6,7},{CR5C,7,7} */ +/* VT3314 and Later: {CR56,0,7},{CR54,6,7},{CR5C,7,7}, {CR5D,7,7} */ +#define IGA2_HOR_SYNC_START_REG_NUM 4 + +/* location: {CR57,0,7},{CR5C,6,6} */ +#define IGA2_HOR_SYNC_END_REG_NUM 2 +/* location: {CR58,0,7},{CR5D,0,2} */ +#define IGA2_VER_TOTAL_REG_NUM 2 +/* location: {CR59,0,7},{CR5D,3,5} */ +#define IGA2_VER_ADDR_REG_NUM 2 +/* location: {CR5A,0,7},{CR5C,0,2} */ +#define IGA2_VER_BLANK_START_REG_NUM 2 +/* location: {CR5E,0,7},{CR5C,3,5} */ +#define IGA2_VER_BLANK_END_REG_NUM 2 +/* location: {CR5E,0,7},{CR5F,5,7} */ +#define IGA2_VER_SYNC_START_REG_NUM 2 +/* location: {CR5F,0,4} */ +#define IGA2_VER_SYNC_END_REG_NUM 1 + +/* Define Offset and Fetch Count Register*/ + +/* location: {CR13,0,7},{CR35,5,7} */ +#define IGA1_OFFSET_REG_NUM 2 +/* 8 bytes alignment. */ +#define IGA1_OFFSER_ALIGN_BYTE 8 +/* x: H resolution, y: color depth */ +#define IGA1_OFFSET_FORMULA(x, y) ((x*y)/IGA1_OFFSER_ALIGN_BYTE) +/* location: {SR1C,0,7},{SR1D,0,1} */ +#define IGA1_FETCH_COUNT_REG_NUM 2 +/* 16 bytes alignment. */ +#define IGA1_FETCH_COUNT_ALIGN_BYTE 16 +/* x: H resolution, y: color depth */ +#define IGA1_FETCH_COUNT_PATCH_VALUE 4 +#define IGA1_FETCH_COUNT_FORMULA(x, y) \ + (((x*y)/IGA1_FETCH_COUNT_ALIGN_BYTE) + IGA1_FETCH_COUNT_PATCH_VALUE) + +/* location: {CR66,0,7},{CR67,0,1} */ +#define IGA2_OFFSET_REG_NUM 2 +#define IGA2_OFFSET_ALIGN_BYTE 8 +/* x: H resolution, y: color depth */ +#define IGA2_OFFSET_FORMULA(x, y) ((x*y)/IGA2_OFFSET_ALIGN_BYTE) +/* location: {CR65,0,7},{CR67,2,3} */ +#define IGA2_FETCH_COUNT_REG_NUM 2 +#define IGA2_FETCH_COUNT_ALIGN_BYTE 16 +#define IGA2_FETCH_COUNT_PATCH_VALUE 0 +#define IGA2_FETCH_COUNT_FORMULA(x, y) \ + (((x*y)/IGA2_FETCH_COUNT_ALIGN_BYTE) + IGA2_FETCH_COUNT_PATCH_VALUE) + +/* Staring Address*/ + +/* location: {CR0C,0,7},{CR0D,0,7},{CR34,0,7},{CR48,0,1} */ +#define IGA1_STARTING_ADDR_REG_NUM 4 +/* location: {CR62,1,7},{CR63,0,7},{CR64,0,7} */ +#define IGA2_STARTING_ADDR_REG_NUM 3 + +/* Define Display OFFSET*/ +/* These value are by HW suggested value*/ +/* location: {SR17,0,7} */ +#define K800_IGA1_FIFO_MAX_DEPTH 384 +/* location: {SR16,0,5},{SR16,7,7} */ +#define K800_IGA1_FIFO_THRESHOLD 328 +/* location: {SR18,0,5},{SR18,7,7} */ +#define K800_IGA1_FIFO_HIGH_THRESHOLD 296 +/* location: {SR22,0,4}. (128/4) =64, K800 must be set zero, */ + /* because HW only 5 bits */ +#define K800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0 + +/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ +#define K800_IGA2_FIFO_MAX_DEPTH 384 +/* location: {CR68,0,3},{CR95,4,6} */ +#define K800_IGA2_FIFO_THRESHOLD 328 +/* location: {CR92,0,3},{CR95,0,2} */ +#define K800_IGA2_FIFO_HIGH_THRESHOLD 296 +/* location: {CR94,0,6} */ +#define K800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 + +/* location: {SR17,0,7} */ +#define P880_IGA1_FIFO_MAX_DEPTH 192 +/* location: {SR16,0,5},{SR16,7,7} */ +#define P880_IGA1_FIFO_THRESHOLD 128 +/* location: {SR18,0,5},{SR18,7,7} */ +#define P880_IGA1_FIFO_HIGH_THRESHOLD 64 +/* location: {SR22,0,4}. (128/4) =64, K800 must be set zero, */ + /* because HW only 5 bits */ +#define P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0 + +/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ +#define P880_IGA2_FIFO_MAX_DEPTH 96 +/* location: {CR68,0,3},{CR95,4,6} */ +#define P880_IGA2_FIFO_THRESHOLD 64 +/* location: {CR92,0,3},{CR95,0,2} */ +#define P880_IGA2_FIFO_HIGH_THRESHOLD 32 +/* location: {CR94,0,6} */ +#define P880_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 + +/* VT3314 chipset*/ + +/* location: {SR17,0,7} */ +#define CN700_IGA1_FIFO_MAX_DEPTH 96 +/* location: {SR16,0,5},{SR16,7,7} */ +#define CN700_IGA1_FIFO_THRESHOLD 80 +/* location: {SR18,0,5},{SR18,7,7} */ +#define CN700_IGA1_FIFO_HIGH_THRESHOLD 64 +/* location: {SR22,0,4}. (128/4) =64, P800 must be set zero, + because HW only 5 bits */ +#define CN700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0 +/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ +#define CN700_IGA2_FIFO_MAX_DEPTH 96 +/* location: {CR68,0,3},{CR95,4,6} */ +#define CN700_IGA2_FIFO_THRESHOLD 80 +/* location: {CR92,0,3},{CR95,0,2} */ +#define CN700_IGA2_FIFO_HIGH_THRESHOLD 32 +/* location: {CR94,0,6} */ +#define CN700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 + +/* For VT3324, these values are suggested by HW */ +/* location: {SR17,0,7} */ +#define CX700_IGA1_FIFO_MAX_DEPTH 192 +/* location: {SR16,0,5},{SR16,7,7} */ +#define CX700_IGA1_FIFO_THRESHOLD 128 +/* location: {SR18,0,5},{SR18,7,7} */ +#define CX700_IGA1_FIFO_HIGH_THRESHOLD 128 +/* location: {SR22,0,4} */ +#define CX700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 124 + +/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ +#define CX700_IGA2_FIFO_MAX_DEPTH 96 +/* location: {CR68,0,3},{CR95,4,6} */ +#define CX700_IGA2_FIFO_THRESHOLD 64 +/* location: {CR92,0,3},{CR95,0,2} */ +#define CX700_IGA2_FIFO_HIGH_THRESHOLD 32 +/* location: {CR94,0,6} */ +#define CX700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 + +/* VT3336 chipset*/ +/* location: {SR17,0,7} */ +#define K8M890_IGA1_FIFO_MAX_DEPTH 360 +/* location: {SR16,0,5},{SR16,7,7} */ +#define K8M890_IGA1_FIFO_THRESHOLD 328 +/* location: {SR18,0,5},{SR18,7,7} */ +#define K8M890_IGA1_FIFO_HIGH_THRESHOLD 296 +/* location: {SR22,0,4}. */ +#define K8M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 124 + +/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ +#define K8M890_IGA2_FIFO_MAX_DEPTH 360 +/* location: {CR68,0,3},{CR95,4,6} */ +#define K8M890_IGA2_FIFO_THRESHOLD 328 +/* location: {CR92,0,3},{CR95,0,2} */ +#define K8M890_IGA2_FIFO_HIGH_THRESHOLD 296 +/* location: {CR94,0,6} */ +#define K8M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 124 + +/* VT3327 chipset*/ +/* location: {SR17,0,7} */ +#define P4M890_IGA1_FIFO_MAX_DEPTH 96 +/* location: {SR16,0,5},{SR16,7,7} */ +#define P4M890_IGA1_FIFO_THRESHOLD 76 +/* location: {SR18,0,5},{SR18,7,7} */ +#define P4M890_IGA1_FIFO_HIGH_THRESHOLD 64 +/* location: {SR22,0,4}. (32/4) =8 */ +#define P4M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 32 +/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ +#define P4M890_IGA2_FIFO_MAX_DEPTH 96 +/* location: {CR68,0,3},{CR95,4,6} */ +#define P4M890_IGA2_FIFO_THRESHOLD 76 +/* location: {CR92,0,3},{CR95,0,2} */ +#define P4M890_IGA2_FIFO_HIGH_THRESHOLD 64 +/* location: {CR94,0,6} */ +#define P4M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 32 + +/* VT3364 chipset*/ +/* location: {SR17,0,7} */ +#define P4M900_IGA1_FIFO_MAX_DEPTH 96 +/* location: {SR16,0,5},{SR16,7,7} */ +#define P4M900_IGA1_FIFO_THRESHOLD 76 +/* location: {SR18,0,5},{SR18,7,7} */ +#define P4M900_IGA1_FIFO_HIGH_THRESHOLD 76 +/* location: {SR22,0,4}. */ +#define P4M900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 32 +/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ +#define P4M900_IGA2_FIFO_MAX_DEPTH 96 +/* location: {CR68,0,3},{CR95,4,6} */ +#define P4M900_IGA2_FIFO_THRESHOLD 76 +/* location: {CR92,0,3},{CR95,0,2} */ +#define P4M900_IGA2_FIFO_HIGH_THRESHOLD 76 +/* location: {CR94,0,6} */ +#define P4M900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 32 + +/* For VT3353, these values are suggested by HW */ +/* location: {SR17,0,7} */ +#define VX800_IGA1_FIFO_MAX_DEPTH 192 +/* location: {SR16,0,5},{SR16,7,7} */ +#define VX800_IGA1_FIFO_THRESHOLD 152 +/* location: {SR18,0,5},{SR18,7,7} */ +#define VX800_IGA1_FIFO_HIGH_THRESHOLD 152 +/* location: {SR22,0,4} */ +#define VX800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 64 +/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */ +#define VX800_IGA2_FIFO_MAX_DEPTH 96 +/* location: {CR68,0,3},{CR95,4,6} */ +#define VX800_IGA2_FIFO_THRESHOLD 64 +/* location: {CR92,0,3},{CR95,0,2} */ +#define VX800_IGA2_FIFO_HIGH_THRESHOLD 32 +/* location: {CR94,0,6} */ +#define VX800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128 + +#define IGA1_FIFO_DEPTH_SELECT_REG_NUM 1 +#define IGA1_FIFO_THRESHOLD_REG_NUM 2 +#define IGA1_FIFO_HIGH_THRESHOLD_REG_NUM 2 +#define IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM 1 + +#define IGA2_FIFO_DEPTH_SELECT_REG_NUM 3 +#define IGA2_FIFO_THRESHOLD_REG_NUM 2 +#define IGA2_FIFO_HIGH_THRESHOLD_REG_NUM 2 +#define IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM 1 + +#define IGA1_FIFO_DEPTH_SELECT_FORMULA(x) ((x/2)-1) +#define IGA1_FIFO_THRESHOLD_FORMULA(x) (x/4) +#define IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(x) (x/4) +#define IGA1_FIFO_HIGH_THRESHOLD_FORMULA(x) (x/4) +#define IGA2_FIFO_DEPTH_SELECT_FORMULA(x) (((x/2)/4)-1) +#define IGA2_FIFO_THRESHOLD_FORMULA(x) (x/4) +#define IGA2_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(x) (x/4) +#define IGA2_FIFO_HIGH_THRESHOLD_FORMULA(x) (x/4) + +/************************************************************************/ +/* LCD Timing */ +/************************************************************************/ + +/* 500 ms = 500000 us */ +#define LCD_POWER_SEQ_TD0 500000 +/* 50 ms = 50000 us */ +#define LCD_POWER_SEQ_TD1 50000 +/* 0 us */ +#define LCD_POWER_SEQ_TD2 0 +/* 210 ms = 210000 us */ +#define LCD_POWER_SEQ_TD3 210000 +/* 2^10 * (1/14.31818M) = 71.475 us (K400.revA) */ +#define CLE266_POWER_SEQ_UNIT 71 +/* 2^11 * (1/14.31818M) = 142.95 us (K400.revB) */ +#define K800_POWER_SEQ_UNIT 142 +/* 2^13 * (1/14.31818M) = 572.1 us */ +#define P880_POWER_SEQ_UNIT 572 + +#define CLE266_POWER_SEQ_FORMULA(x) ((x)/CLE266_POWER_SEQ_UNIT) +#define K800_POWER_SEQ_FORMULA(x) ((x)/K800_POWER_SEQ_UNIT) +#define P880_POWER_SEQ_FORMULA(x) ((x)/P880_POWER_SEQ_UNIT) + +/* location: {CR8B,0,7},{CR8F,0,3} */ +#define LCD_POWER_SEQ_TD0_REG_NUM 2 +/* location: {CR8C,0,7},{CR8F,4,7} */ +#define LCD_POWER_SEQ_TD1_REG_NUM 2 +/* location: {CR8D,0,7},{CR90,0,3} */ +#define LCD_POWER_SEQ_TD2_REG_NUM 2 +/* location: {CR8E,0,7},{CR90,4,7} */ +#define LCD_POWER_SEQ_TD3_REG_NUM 2 + +/* LCD Scaling factor*/ +/* x: indicate setting horizontal size*/ +/* y: indicate panel horizontal size*/ + +/* Horizontal scaling factor 10 bits (2^10) */ +#define CLE266_LCD_HOR_SCF_FORMULA(x, y) (((x-1)*1024)/(y-1)) +/* Vertical scaling factor 10 bits (2^10) */ +#define CLE266_LCD_VER_SCF_FORMULA(x, y) (((x-1)*1024)/(y-1)) +/* Horizontal scaling factor 10 bits (2^12) */ +#define K800_LCD_HOR_SCF_FORMULA(x, y) (((x-1)*4096)/(y-1)) +/* Vertical scaling factor 10 bits (2^11) */ +#define K800_LCD_VER_SCF_FORMULA(x, y) (((x-1)*2048)/(y-1)) + +/* location: {CR9F,0,1},{CR77,0,7},{CR79,4,5} */ +#define LCD_HOR_SCALING_FACTOR_REG_NUM 3 +/* location: {CR79,3,3},{CR78,0,7},{CR79,6,7} */ +#define LCD_VER_SCALING_FACTOR_REG_NUM 3 +/* location: {CR77,0,7},{CR79,4,5} */ +#define LCD_HOR_SCALING_FACTOR_REG_NUM_CLE 2 +/* location: {CR78,0,7},{CR79,6,7} */ +#define LCD_VER_SCALING_FACTOR_REG_NUM_CLE 2 + +/************************************************ + ***** Define IGA1 Display Timing ***** + ************************************************/ +struct io_register { + u8 io_addr; + u8 start_bit; + u8 end_bit; +}; + +/* IGA1 Horizontal Total */ +struct iga1_hor_total { + int reg_num; + struct io_register reg[IGA1_HOR_TOTAL_REG_NUM]; +}; + +/* IGA1 Horizontal Addressable Video */ +struct iga1_hor_addr { + int reg_num; + struct io_register reg[IGA1_HOR_ADDR_REG_NUM]; +}; + +/* IGA1 Horizontal Blank Start */ +struct iga1_hor_blank_start { + int reg_num; + struct io_register reg[IGA1_HOR_BLANK_START_REG_NUM]; +}; + +/* IGA1 Horizontal Blank End */ +struct iga1_hor_blank_end { + int reg_num; + struct io_register reg[IGA1_HOR_BLANK_END_REG_NUM]; +}; + +/* IGA1 Horizontal Sync Start */ +struct iga1_hor_sync_start { + int reg_num; + struct io_register reg[IGA1_HOR_SYNC_START_REG_NUM]; +}; + +/* IGA1 Horizontal Sync End */ +struct iga1_hor_sync_end { + int reg_num; + struct io_register reg[IGA1_HOR_SYNC_END_REG_NUM]; +}; + +/* IGA1 Vertical Total */ +struct iga1_ver_total { + int reg_num; + struct io_register reg[IGA1_VER_TOTAL_REG_NUM]; +}; + +/* IGA1 Vertical Addressable Video */ +struct iga1_ver_addr { + int reg_num; + struct io_register reg[IGA1_VER_ADDR_REG_NUM]; +}; + +/* IGA1 Vertical Blank Start */ +struct iga1_ver_blank_start { + int reg_num; + struct io_register reg[IGA1_VER_BLANK_START_REG_NUM]; +}; + +/* IGA1 Vertical Blank End */ +struct iga1_ver_blank_end { + int reg_num; + struct io_register reg[IGA1_VER_BLANK_END_REG_NUM]; +}; + +/* IGA1 Vertical Sync Start */ +struct iga1_ver_sync_start { + int reg_num; + struct io_register reg[IGA1_VER_SYNC_START_REG_NUM]; +}; + +/* IGA1 Vertical Sync End */ +struct iga1_ver_sync_end { + int reg_num; + struct io_register reg[IGA1_VER_SYNC_END_REG_NUM]; +}; + +/***************************************************** +** Define IGA2 Shadow Display Timing **** +*****************************************************/ + +/* IGA2 Shadow Horizontal Total */ +struct iga2_shadow_hor_total { + int reg_num; + struct io_register reg[IGA2_SHADOW_HOR_TOTAL_REG_NUM]; +}; + +/* IGA2 Shadow Horizontal Blank End */ +struct iga2_shadow_hor_blank_end { + int reg_num; + struct io_register reg[IGA2_SHADOW_HOR_BLANK_END_REG_NUM]; +}; + +/* IGA2 Shadow Vertical Total */ +struct iga2_shadow_ver_total { + int reg_num; + struct io_register reg[IGA2_SHADOW_VER_TOTAL_REG_NUM]; +}; + +/* IGA2 Shadow Vertical Addressable Video */ +struct iga2_shadow_ver_addr { + int reg_num; + struct io_register reg[IGA2_SHADOW_VER_ADDR_REG_NUM]; +}; + +/* IGA2 Shadow Vertical Blank Start */ +struct iga2_shadow_ver_blank_start { + int reg_num; + struct io_register reg[IGA2_SHADOW_VER_BLANK_START_REG_NUM]; +}; + +/* IGA2 Shadow Vertical Blank End */ +struct iga2_shadow_ver_blank_end { + int reg_num; + struct io_register reg[IGA2_SHADOW_VER_BLANK_END_REG_NUM]; +}; + +/* IGA2 Shadow Vertical Sync Start */ +struct iga2_shadow_ver_sync_start { + int reg_num; + struct io_register reg[IGA2_SHADOW_VER_SYNC_START_REG_NUM]; +}; + +/* IGA2 Shadow Vertical Sync End */ +struct iga2_shadow_ver_sync_end { + int reg_num; + struct io_register reg[IGA2_SHADOW_VER_SYNC_END_REG_NUM]; +}; + +/***************************************************** +** Define IGA2 Display Timing **** +******************************************************/ + +/* IGA2 Horizontal Total */ +struct iga2_hor_total { + int reg_num; + struct io_register reg[IGA2_HOR_TOTAL_REG_NUM]; +}; + +/* IGA2 Horizontal Addressable Video */ +struct iga2_hor_addr { + int reg_num; + struct io_register reg[IGA2_HOR_ADDR_REG_NUM]; +}; + +/* IGA2 Horizontal Blank Start */ +struct iga2_hor_blank_start { + int reg_num; + struct io_register reg[IGA2_HOR_BLANK_START_REG_NUM]; +}; + +/* IGA2 Horizontal Blank End */ +struct iga2_hor_blank_end { + int reg_num; + struct io_register reg[IGA2_HOR_BLANK_END_REG_NUM]; +}; + +/* IGA2 Horizontal Sync Start */ +struct iga2_hor_sync_start { + int reg_num; + struct io_register reg[IGA2_HOR_SYNC_START_REG_NUM]; +}; + +/* IGA2 Horizontal Sync End */ +struct iga2_hor_sync_end { + int reg_num; + struct io_register reg[IGA2_HOR_SYNC_END_REG_NUM]; +}; + +/* IGA2 Vertical Total */ +struct iga2_ver_total { + int reg_num; + struct io_register reg[IGA2_VER_TOTAL_REG_NUM]; +}; + +/* IGA2 Vertical Addressable Video */ +struct iga2_ver_addr { + int reg_num; + struct io_register reg[IGA2_VER_ADDR_REG_NUM]; +}; + +/* IGA2 Vertical Blank Start */ +struct iga2_ver_blank_start { + int reg_num; + struct io_register reg[IGA2_VER_BLANK_START_REG_NUM]; +}; + +/* IGA2 Vertical Blank End */ +struct iga2_ver_blank_end { + int reg_num; + struct io_register reg[IGA2_VER_BLANK_END_REG_NUM]; +}; + +/* IGA2 Vertical Sync Start */ +struct iga2_ver_sync_start { + int reg_num; + struct io_register reg[IGA2_VER_SYNC_START_REG_NUM]; +}; + +/* IGA2 Vertical Sync End */ +struct iga2_ver_sync_end { + int reg_num; + struct io_register reg[IGA2_VER_SYNC_END_REG_NUM]; +}; + +/* IGA1 Offset Register */ +struct iga1_offset { + int reg_num; + struct io_register reg[IGA1_OFFSET_REG_NUM]; +}; + +/* IGA2 Offset Register */ +struct iga2_offset { + int reg_num; + struct io_register reg[IGA2_OFFSET_REG_NUM]; +}; + +struct offset { + struct iga1_offset iga1_offset_reg; + struct iga2_offset iga2_offset_reg; +}; + +/* IGA1 Fetch Count Register */ +struct iga1_fetch_count { + int reg_num; + struct io_register reg[IGA1_FETCH_COUNT_REG_NUM]; +}; + +/* IGA2 Fetch Count Register */ +struct iga2_fetch_count { + int reg_num; + struct io_register reg[IGA2_FETCH_COUNT_REG_NUM]; +}; + +struct fetch_count { + struct iga1_fetch_count iga1_fetch_count_reg; + struct iga2_fetch_count iga2_fetch_count_reg; +}; + +/* Starting Address Register */ +struct iga1_starting_addr { + int reg_num; + struct io_register reg[IGA1_STARTING_ADDR_REG_NUM]; +}; + +struct iga2_starting_addr { + int reg_num; + struct io_register reg[IGA2_STARTING_ADDR_REG_NUM]; +}; + +struct starting_addr { + struct iga1_starting_addr iga1_starting_addr_reg; + struct iga2_starting_addr iga2_starting_addr_reg; +}; + +/* LCD Power Sequence Timer */ +struct lcd_pwd_seq_td0 { + int reg_num; + struct io_register reg[LCD_POWER_SEQ_TD0_REG_NUM]; +}; + +struct lcd_pwd_seq_td1 { + int reg_num; + struct io_register reg[LCD_POWER_SEQ_TD1_REG_NUM]; +}; + +struct lcd_pwd_seq_td2 { + int reg_num; + struct io_register reg[LCD_POWER_SEQ_TD2_REG_NUM]; +}; + +struct lcd_pwd_seq_td3 { + int reg_num; + struct io_register reg[LCD_POWER_SEQ_TD3_REG_NUM]; +}; + +struct _lcd_pwd_seq_timer { + struct lcd_pwd_seq_td0 td0; + struct lcd_pwd_seq_td1 td1; + struct lcd_pwd_seq_td2 td2; + struct lcd_pwd_seq_td3 td3; +}; + +/* LCD Scaling Factor */ +struct _lcd_hor_scaling_factor { + int reg_num; + struct io_register reg[LCD_HOR_SCALING_FACTOR_REG_NUM]; +}; + +struct _lcd_ver_scaling_factor { + int reg_num; + struct io_register reg[LCD_VER_SCALING_FACTOR_REG_NUM]; +}; + +struct _lcd_scaling_factor { + struct _lcd_hor_scaling_factor lcd_hor_scaling_factor; + struct _lcd_ver_scaling_factor lcd_ver_scaling_factor; +}; + +struct pll_map { + u32 clk; + u32 cle266_pll; + u32 k800_pll; + u32 cx700_pll; +}; + +struct rgbLUT { + u8 red; + u8 green; + u8 blue; +}; + +struct lcd_pwd_seq_timer { + u16 td0; + u16 td1; + u16 td2; + u16 td3; +}; + +/* Display FIFO Relation Registers*/ +struct iga1_fifo_depth_select { + int reg_num; + struct io_register reg[IGA1_FIFO_DEPTH_SELECT_REG_NUM]; +}; + +struct iga1_fifo_threshold_select { + int reg_num; + struct io_register reg[IGA1_FIFO_THRESHOLD_REG_NUM]; +}; + +struct iga1_fifo_high_threshold_select { + int reg_num; + struct io_register reg[IGA1_FIFO_HIGH_THRESHOLD_REG_NUM]; +}; + +struct iga1_display_queue_expire_num { + int reg_num; + struct io_register reg[IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM]; +}; + +struct iga2_fifo_depth_select { + int reg_num; + struct io_register reg[IGA2_FIFO_DEPTH_SELECT_REG_NUM]; +}; + +struct iga2_fifo_threshold_select { + int reg_num; + struct io_register reg[IGA2_FIFO_THRESHOLD_REG_NUM]; +}; + +struct iga2_fifo_high_threshold_select { + int reg_num; + struct io_register reg[IGA2_FIFO_HIGH_THRESHOLD_REG_NUM]; +}; + +struct iga2_display_queue_expire_num { + int reg_num; + struct io_register reg[IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM]; +}; + +struct fifo_depth_select { + struct iga1_fifo_depth_select iga1_fifo_depth_select_reg; + struct iga2_fifo_depth_select iga2_fifo_depth_select_reg; +}; + +struct fifo_threshold_select { + struct iga1_fifo_threshold_select iga1_fifo_threshold_select_reg; + struct iga2_fifo_threshold_select iga2_fifo_threshold_select_reg; +}; + +struct fifo_high_threshold_select { + struct iga1_fifo_high_threshold_select + iga1_fifo_high_threshold_select_reg; + struct iga2_fifo_high_threshold_select + iga2_fifo_high_threshold_select_reg; +}; + +struct display_queue_expire_num { + struct iga1_display_queue_expire_num + iga1_display_queue_expire_num_reg; + struct iga2_display_queue_expire_num + iga2_display_queue_expire_num_reg; +}; + +struct iga1_crtc_timing { + struct iga1_hor_total hor_total; + struct iga1_hor_addr hor_addr; + struct iga1_hor_blank_start hor_blank_start; + struct iga1_hor_blank_end hor_blank_end; + struct iga1_hor_sync_start hor_sync_start; + struct iga1_hor_sync_end hor_sync_end; + struct iga1_ver_total ver_total; + struct iga1_ver_addr ver_addr; + struct iga1_ver_blank_start ver_blank_start; + struct iga1_ver_blank_end ver_blank_end; + struct iga1_ver_sync_start ver_sync_start; + struct iga1_ver_sync_end ver_sync_end; +}; + +struct iga2_shadow_crtc_timing { + struct iga2_shadow_hor_total hor_total_shadow; + struct iga2_shadow_hor_blank_end hor_blank_end_shadow; + struct iga2_shadow_ver_total ver_total_shadow; + struct iga2_shadow_ver_addr ver_addr_shadow; + struct iga2_shadow_ver_blank_start ver_blank_start_shadow; + struct iga2_shadow_ver_blank_end ver_blank_end_shadow; + struct iga2_shadow_ver_sync_start ver_sync_start_shadow; + struct iga2_shadow_ver_sync_end ver_sync_end_shadow; +}; + +struct iga2_crtc_timing { + struct iga2_hor_total hor_total; + struct iga2_hor_addr hor_addr; + struct iga2_hor_blank_start hor_blank_start; + struct iga2_hor_blank_end hor_blank_end; + struct iga2_hor_sync_start hor_sync_start; + struct iga2_hor_sync_end hor_sync_end; + struct iga2_ver_total ver_total; + struct iga2_ver_addr ver_addr; + struct iga2_ver_blank_start ver_blank_start; + struct iga2_ver_blank_end ver_blank_end; + struct iga2_ver_sync_start ver_sync_start; + struct iga2_ver_sync_end ver_sync_end; +}; + +/* device ID */ +#define CLE266 0x3123 +#define KM400 0x3205 +#define CN400_FUNCTION2 0x2259 +#define CN400_FUNCTION3 0x3259 +/* support VT3314 chipset */ +#define CN700_FUNCTION2 0x2314 +#define CN700_FUNCTION3 0x3208 +/* VT3324 chipset */ +#define CX700_FUNCTION2 0x2324 +#define CX700_FUNCTION3 0x3324 +/* VT3204 chipset*/ +#define KM800_FUNCTION3 0x3204 +/* VT3336 chipset*/ +#define KM890_FUNCTION3 0x3336 +/* VT3327 chipset*/ +#define P4M890_FUNCTION3 0x3327 +/* VT3293 chipset*/ +#define CN750_FUNCTION3 0x3208 +/* VT3364 chipset*/ +#define P4M900_FUNCTION3 0x3364 +/* VT3353 chipset*/ +#define VX800_FUNCTION3 0x3353 + +#define NUM_TOTAL_PLL_TABLE ARRAY_SIZE(pll_value) + +struct IODATA { + u8 Index; + u8 Mask; + u8 Data; +}; + +struct pci_device_id_info { + u32 vendor; + u32 device; + u32 chip_index; +}; + +extern unsigned int viafb_second_virtual_xres; +extern unsigned int viafb_second_offset; +extern int viafb_second_size; +extern int viafb_SAMM_ON; +extern int viafb_dual_fb; +extern int viafb_LCD2_ON; +extern int viafb_LCD_ON; +extern int viafb_DVI_ON; +extern int viafb_accel; +extern int viafb_hotplug; + +void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask); +void viafb_set_output_path(int device, int set_iga, + int output_interface); +void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, + int mode_index, int bpp_byte, int set_iga); + +void viafb_set_vclock(u32 CLK, int set_iga); +void viafb_load_reg(int timing_value, int viafb_load_reg_num, + struct io_register *reg, + int io_type); +void viafb_crt_disable(void); +void viafb_crt_enable(void); +void init_ad9389(void); +/* Access I/O Function */ +void viafb_write_reg(u8 index, u16 io_port, u8 data); +u8 viafb_read_reg(int io_port, u8 index); +void viafb_lock_crt(void); +void viafb_unlock_crt(void); +void viafb_load_offset_reg(int h_addr, int bpp_byte, int set_iga); +void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga); +void viafb_write_regx(struct io_reg RegTable[], int ItemNum); +struct VideoModeTable *viafb_get_modetbl_pointer(int Index); +u32 viafb_get_clk_value(int clk); +void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active); +void viafb_set_color_depth(int bpp_byte, int set_iga); +void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ + *p_gfx_dpa_setting); + +int viafb_setmode(int vmode_index, int hor_res, int ver_res, + int video_bpp, int vmode_index1, int hor_res1, + int ver_res1, int video_bpp1); +void viafb_init_chip_info(void); +void viafb_init_dac(int set_iga); +int viafb_get_pixclock(int hres, int vres, int vmode_refresh); +int viafb_get_refresh(int hres, int vres, u32 float_refresh); +void viafb_update_device_setting(int hres, int vres, int bpp, + int vmode_refresh, int flag); +void viafb_get_mmio_info(unsigned long *mmio_base, + unsigned long *mmio_len); + +void viafb_set_iga_path(void); +void viafb_set_start_addr(void); +void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len); + +#endif /* __HW_H__ */ diff --git a/drivers/video/via/iface.c b/drivers/video/via/iface.c new file mode 100644 index 00000000000..1570636c8d5 --- /dev/null +++ b/drivers/video/via/iface.c @@ -0,0 +1,78 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" + +/* Get frame buffer size from VGA BIOS */ + +unsigned int viafb_get_memsize(void) +{ + unsigned int m; + + /* If memory size provided by user */ + if (viafb_memsize) + m = viafb_memsize * Mb; + else { + m = (unsigned int)viafb_read_reg(VIASR, SR39); + m = m * (4 * Mb); + + if ((m < (16 * Mb)) || (m > (64 * Mb))) + m = 16 * Mb; + } + DEBUG_MSG(KERN_INFO "framebuffer size = %d Mb\n", m / Mb); + return m; +} + +/* Get Video Buffer Starting Physical Address(back door)*/ + +unsigned long viafb_get_videobuf_addr(void) +{ + struct pci_dev *pdev = NULL; + unsigned char sys_mem; + unsigned char video_mem; + unsigned long sys_mem_size; + unsigned long video_mem_size; + /*system memory = 256 MB, video memory 64 MB */ + unsigned long vmem_starting_adr = 0x0C000000; + + pdev = + (struct pci_dev *)pci_get_device(VIA_K800_BRIDGE_VID, + VIA_K800_BRIDGE_DID, NULL); + if (pdev != NULL) { + pci_read_config_byte(pdev, VIA_K800_SYSTEM_MEMORY_REG, + &sys_mem); + pci_read_config_byte(pdev, VIA_K800_VIDEO_MEMORY_REG, + &video_mem); + video_mem = (video_mem & 0x70) >> 4; + sys_mem_size = ((unsigned long)sys_mem) << 24; + if (video_mem != 0) + video_mem_size = (1 << (video_mem)) * 1024 * 1024; + else + video_mem_size = 0; + + vmem_starting_adr = sys_mem_size - video_mem_size; + pci_dev_put(pdev); + } + + DEBUG_MSG(KERN_INFO "Video Memory Starting Address = %lx \n", + vmem_starting_adr); + return vmem_starting_adr; +} diff --git a/drivers/video/via/iface.h b/drivers/video/via/iface.h new file mode 100644 index 00000000000..790ec3e3aea --- /dev/null +++ b/drivers/video/via/iface.h @@ -0,0 +1,38 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IFACE_H__ +#define __IFACE_H__ + +#define Kb (1024) +#define Mb (Kb*Kb) + +#define VIA_K800_BRIDGE_VID 0x1106 +#define VIA_K800_BRIDGE_DID 0x3204 + +#define VIA_K800_SYSTEM_MEMORY_REG 0x47 +#define VIA_K800_VIDEO_MEMORY_REG 0xA1 + +extern int viafb_memsize; +unsigned int viafb_get_memsize(void); +unsigned long viafb_get_videobuf_addr(void); + +#endif /* __IFACE_H__ */ diff --git a/drivers/video/via/ioctl.c b/drivers/video/via/ioctl.c new file mode 100644 index 00000000000..da03c074e32 --- /dev/null +++ b/drivers/video/via/ioctl.c @@ -0,0 +1,112 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" + +int viafb_ioctl_get_viafb_info(u_long arg) +{ + struct viafb_ioctl_info viainfo; + + viainfo.viafb_id = VIAID; + viainfo.vendor_id = PCI_VIA_VENDOR_ID; + + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + viainfo.device_id = UNICHROME_CLE266_DID; + break; + + case UNICHROME_K400: + viainfo.device_id = UNICHROME_K400_DID; + break; + + case UNICHROME_K800: + viainfo.device_id = UNICHROME_K800_DID; + break; + + case UNICHROME_PM800: + viainfo.device_id = UNICHROME_PM800_DID; + break; + + case UNICHROME_CN700: + viainfo.device_id = UNICHROME_CN700_DID; + break; + + case UNICHROME_CX700: + viainfo.device_id = UNICHROME_CX700_DID; + break; + + case UNICHROME_K8M890: + viainfo.device_id = UNICHROME_K8M890_DID; + break; + + case UNICHROME_P4M890: + viainfo.device_id = UNICHROME_P4M890_DID; + break; + + case UNICHROME_P4M900: + viainfo.device_id = UNICHROME_P4M900_DID; + break; + } + + viainfo.version = VERSION_MAJOR; + viainfo.revision = VERSION_MINOR; + + if (copy_to_user((void __user *)arg, &viainfo, sizeof(viainfo))) + return -EFAULT; + + return 0; +} + +/* Hot-Plug Priority: DVI > CRT*/ +int viafb_ioctl_hotplug(int hres, int vres, int bpp) +{ + int DVIsense, status = 0; + DEBUG_MSG(KERN_INFO "viafb_ioctl_hotplug!!\n"); + + if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name != + NON_TMDS_TRANSMITTER) { + DVIsense = viafb_dvi_sense(); + + if (DVIsense) { + DEBUG_MSG(KERN_INFO "DVI Attached...\n"); + if (viafb_DeviceStatus != DVI_Device) { + viafb_DVI_ON = 1; + viafb_CRT_ON = 0; + viafb_LCD_ON = 0; + viafb_DeviceStatus = DVI_Device; + return viafb_DeviceStatus; + } + status = 1; + } else + DEBUG_MSG(KERN_INFO "DVI De-attached...\n"); + } + + if ((viafb_DeviceStatus != CRT_Device) && (status == 0)) { + viafb_CRT_ON = 1; + viafb_DVI_ON = 0; + viafb_LCD_ON = 0; + + viafb_DeviceStatus = CRT_Device; + return viafb_DeviceStatus; + } + + return 0; +} diff --git a/drivers/video/via/ioctl.h b/drivers/video/via/ioctl.h new file mode 100644 index 00000000000..842fe30b986 --- /dev/null +++ b/drivers/video/via/ioctl.h @@ -0,0 +1,210 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __IOCTL_H__ +#define __IOCTL_H__ + +#ifndef __user +#define __user +#endif + +/* VIAFB IOCTL definition */ +#define VIAFB_GET_INFO_SIZE 0x56494101 /* 'VIA\01' */ +#define VIAFB_GET_INFO 0x56494102 /* 'VIA\02' */ +#define VIAFB_HOTPLUG 0x56494103 /* 'VIA\03' */ +#define VIAFB_SET_HOTPLUG_FLAG 0x56494104 /* 'VIA\04' */ +#define VIAFB_GET_RESOLUTION 0x56494105 /* 'VIA\05' */ +#define VIAFB_GET_SAMM_INFO 0x56494107 /* 'VIA\07' */ +#define VIAFB_TURN_ON_OUTPUT_DEVICE 0x56494108 /* 'VIA\08' */ +#define VIAFB_TURN_OFF_OUTPUT_DEVICE 0x56494109 /* 'VIA\09' */ +#define VIAFB_SET_DEVICE 0x5649410A +#define VIAFB_GET_DEVICE 0x5649410B +#define VIAFB_GET_DRIVER_VERSION 0x56494112 /* 'VIA\12' */ +#define VIAFB_GET_CHIP_INFO 0x56494113 /* 'VIA\13' */ +#define VIAFB_SET_DEVICE_INFO 0x56494114 +#define VIAFB_GET_DEVICE_INFO 0x56494115 + +#define VIAFB_GET_DEVICE_SUPPORT 0x56494118 +#define VIAFB_GET_DEVICE_CONNECT 0x56494119 +#define VIAFB_GET_PANEL_SUPPORT_EXPAND 0x5649411A +#define VIAFB_GET_DRIVER_NAME 0x56494122 +#define VIAFB_GET_DEVICE_SUPPORT_STATE 0x56494123 +#define VIAFB_GET_GAMMA_LUT 0x56494124 +#define VIAFB_SET_GAMMA_LUT 0x56494125 +#define VIAFB_GET_GAMMA_SUPPORT_STATE 0x56494126 +#define VIAFB_SET_VIDEO_DEVICE 0x56494127 +#define VIAFB_GET_VIDEO_DEVICE 0x56494128 +#define VIAFB_SET_SECOND_MODE 0x56494129 +#define VIAFB_SYNC_SURFACE 0x56494130 +#define VIAFB_GET_DRIVER_CAPS 0x56494131 +#define VIAFB_GET_IGA_SCALING_INFO 0x56494132 +#define VIAFB_GET_PANEL_MAX_SIZE 0x56494133 +#define VIAFB_GET_PANEL_MAX_POSITION 0x56494134 +#define VIAFB_SET_PANEL_SIZE 0x56494135 +#define VIAFB_SET_PANEL_POSITION 0x56494136 +#define VIAFB_GET_PANEL_POSITION 0x56494137 +#define VIAFB_GET_PANEL_SIZE 0x56494138 + +#define None_Device 0x00 +#define CRT_Device 0x01 +#define LCD_Device 0x02 +#define DVI_Device 0x08 +#define CRT2_Device 0x10 +#define LCD2_Device 0x40 + +#define OP_LCD_CENTERING 0x01 +#define OP_LCD_PANEL_ID 0x02 +#define OP_LCD_MODE 0x03 + +/*SAMM operation flag*/ +#define OP_SAMM 0x80 + +#define LCD_PANEL_ID_MAXIMUM 22 + +#define STATE_ON 0x1 +#define STATE_OFF 0x0 +#define STATE_DEFAULT 0xFFFF + +#define MAX_ACTIVE_DEV_NUM 2 + +struct device_t { + unsigned short crt:1; + unsigned short dvi:1; + unsigned short lcd:1; + unsigned short samm:1; + unsigned short lcd_dsp_cent:1; + unsigned char lcd_mode:1; + unsigned short epia_dvi:1; + unsigned short lcd_dual_edge:1; + unsigned short lcd2:1; + + unsigned short primary_dev; + unsigned char lcd_panel_id; + unsigned short xres, yres; + unsigned short xres1, yres1; + unsigned short refresh; + unsigned short bpp; + unsigned short refresh1; + unsigned short bpp1; + unsigned short sequence; + unsigned short bus_width; +}; + +struct viafb_ioctl_info { + u32 viafb_id; /* for identifying viafb */ +#define VIAID 0x56494146 /* Identify myself with 'VIAF' */ + u16 vendor_id; + u16 device_id; + u8 version; + u8 revision; + u8 reserved[246]; /* for future use */ +}; + +struct viafb_ioctl_mode { + u32 xres; + u32 yres; + u32 refresh; + u32 bpp; + u32 xres_sec; + u32 yres_sec; + u32 virtual_xres_sec; + u32 virtual_yres_sec; + u32 refresh_sec; + u32 bpp_sec; +}; +struct viafb_ioctl_samm { + u32 samm_status; + u32 size_prim; + u32 size_sec; + u32 mem_base; + u32 offset_sec; +}; + +struct viafb_driver_version { + int iMajorNum; + int iKernelNum; + int iOSNum; + int iMinorNum; +}; + +struct viafb_ioctl_lcd_attribute { + unsigned int panel_id; + unsigned int display_center; + unsigned int lcd_mode; +}; + +struct viafb_ioctl_setting { + /* Enable or disable active devices */ + unsigned short device_flag; + /* Indicate which device should be turn on or turn off. */ + unsigned short device_status; + unsigned int reserved; + /* Indicate which LCD's attribute can be changed. */ + unsigned short lcd_operation_flag; + /* 1: SAMM ON 0: SAMM OFF */ + unsigned short samm_status; + /* horizontal resolution of first device */ + unsigned short first_dev_hor_res; + /* vertical resolution of first device */ + unsigned short first_dev_ver_res; + /* horizontal resolution of second device */ + unsigned short second_dev_hor_res; + /* vertical resolution of second device */ + unsigned short second_dev_ver_res; + /* refresh rate of first device */ + unsigned short first_dev_refresh; + /* bpp of first device */ + unsigned short first_dev_bpp; + /* refresh rate of second device */ + unsigned short second_dev_refresh; + /* bpp of second device */ + unsigned short second_dev_bpp; + /* Indicate which device are primary display device. */ + unsigned int primary_device; + /* Indicate which device will show video. only valid in duoview mode */ + unsigned int video_device_status; + unsigned int struct_reserved[34]; + struct viafb_ioctl_lcd_attribute lcd_attributes; +}; + +struct _UTFunctionCaps { + unsigned int dw3DScalingState; + unsigned int reserved[31]; +}; + +struct _POSITIONVALUE { + unsigned int dwX; + unsigned int dwY; +}; + +struct _panel_size_pos_info { + unsigned int device_type; + int x; + int y; +}; + +extern int viafb_LCD_ON; +extern int viafb_DVI_ON; + +int viafb_ioctl_get_viafb_info(u_long arg); +int viafb_ioctl_hotplug(int hres, int vres, int bpp); + +#endif /* __IOCTL_H__ */ diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c new file mode 100644 index 00000000000..6c7290a6a44 --- /dev/null +++ b/drivers/video/via/lcd.c @@ -0,0 +1,1821 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" +#include "lcdtbl.h" + +static struct iga2_shadow_crtc_timing iga2_shadow_crtc_reg = { + /* IGA2 Shadow Horizontal Total */ + {IGA2_SHADOW_HOR_TOTAL_REG_NUM, {{CR6D, 0, 7}, {CR71, 3, 3} } }, + /* IGA2 Shadow Horizontal Blank End */ + {IGA2_SHADOW_HOR_BLANK_END_REG_NUM, {{CR6E, 0, 7} } }, + /* IGA2 Shadow Vertical Total */ + {IGA2_SHADOW_VER_TOTAL_REG_NUM, {{CR6F, 0, 7}, {CR71, 0, 2} } }, + /* IGA2 Shadow Vertical Addressable Video */ + {IGA2_SHADOW_VER_ADDR_REG_NUM, {{CR70, 0, 7}, {CR71, 4, 6} } }, + /* IGA2 Shadow Vertical Blank Start */ + {IGA2_SHADOW_VER_BLANK_START_REG_NUM, + {{CR72, 0, 7}, {CR74, 4, 6} } }, + /* IGA2 Shadow Vertical Blank End */ + {IGA2_SHADOW_VER_BLANK_END_REG_NUM, {{CR73, 0, 7}, {CR74, 0, 2} } }, + /* IGA2 Shadow Vertical Sync Start */ + {IGA2_SHADOW_VER_SYNC_START_REG_NUM, {{CR75, 0, 7}, {CR76, 4, 6} } }, + /* IGA2 Shadow Vertical Sync End */ + {IGA2_SHADOW_VER_SYNC_END_REG_NUM, {{CR76, 0, 3} } } +}; + +static struct _lcd_scaling_factor lcd_scaling_factor = { + /* LCD Horizontal Scaling Factor Register */ + {LCD_HOR_SCALING_FACTOR_REG_NUM, + {{CR9F, 0, 1}, {CR77, 0, 7}, {CR79, 4, 5} } }, + /* LCD Vertical Scaling Factor Register */ + {LCD_VER_SCALING_FACTOR_REG_NUM, + {{CR79, 3, 3}, {CR78, 0, 7}, {CR79, 6, 7} } } +}; +static struct _lcd_scaling_factor lcd_scaling_factor_CLE = { + /* LCD Horizontal Scaling Factor Register */ + {LCD_HOR_SCALING_FACTOR_REG_NUM_CLE, {{CR77, 0, 7}, {CR79, 4, 5} } }, + /* LCD Vertical Scaling Factor Register */ + {LCD_VER_SCALING_FACTOR_REG_NUM_CLE, {{CR78, 0, 7}, {CR79, 6, 7} } } +}; + +static int check_lvds_chip(int device_id_subaddr, int device_id); +static bool lvds_identify_integratedlvds(void); +static int fp_id_to_vindex(int panel_id); +static int lvds_register_read(int index); +static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, + int panel_vres); +static void load_lcd_k400_patch_tbl(int set_hres, int set_vres, + int panel_id); +static void load_lcd_p880_patch_tbl(int set_hres, int set_vres, + int panel_id); +static void load_lcd_patch_regs(int set_hres, int set_vres, + int panel_id, int set_iga); +static void via_pitch_alignment_patch_lcd( + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information + *plvds_chip_info); +static void lcd_patch_skew_dvp0(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +static void lcd_patch_skew_dvp1(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +static void lcd_patch_skew(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information *plvds_chip_info); + +static void integrated_lvds_disable(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +static void integrated_lvds_enable(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +static void lcd_powersequence_off(void); +static void lcd_powersequence_on(void); +static void fill_lcd_format(void); +static void check_diport_of_integrated_lvds( + struct lvds_chip_information *plvds_chip_info, + struct lvds_setting_information + *plvds_setting_info); +static struct display_timing lcd_centering_timging(struct display_timing + mode_crt_reg, + struct display_timing panel_crt_reg); +static void load_crtc_shadow_timing(struct display_timing mode_timing, + struct display_timing panel_timing); +static void viafb_load_scaling_factor_for_p4m900(int set_hres, + int set_vres, int panel_hres, int panel_vres); + +static int check_lvds_chip(int device_id_subaddr, int device_id) +{ + if (lvds_register_read(device_id_subaddr) == device_id) + return OK; + else + return FAIL; +} + +void viafb_init_lcd_size(void) +{ + DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n"); + DEBUG_MSG(KERN_INFO + "viaparinfo->lvds_setting_info->get_lcd_size_method %d\n", + viaparinfo->lvds_setting_info->get_lcd_size_method); + + switch (viaparinfo->lvds_setting_info->get_lcd_size_method) { + case GET_LCD_SIZE_BY_SYSTEM_BIOS: + break; + case GET_LCD_SZIE_BY_HW_STRAPPING: + break; + case GET_LCD_SIZE_BY_VGA_BIOS: + DEBUG_MSG(KERN_INFO "Get LCD Size method by VGA BIOS !!\n"); + viaparinfo->lvds_setting_info->lcd_panel_size = + fp_id_to_vindex(viafb_lcd_panel_id); + DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n", + viaparinfo->lvds_setting_info->lcd_panel_id); + DEBUG_MSG(KERN_INFO "LCD Panel Size = %d\n", + viaparinfo->lvds_setting_info->lcd_panel_size); + break; + case GET_LCD_SIZE_BY_USER_SETTING: + DEBUG_MSG(KERN_INFO "Get LCD Size method by user setting !!\n"); + viaparinfo->lvds_setting_info->lcd_panel_size = + fp_id_to_vindex(viafb_lcd_panel_id); + DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n", + viaparinfo->lvds_setting_info->lcd_panel_id); + DEBUG_MSG(KERN_INFO "LCD Panel Size = %d\n", + viaparinfo->lvds_setting_info->lcd_panel_size); + break; + default: + DEBUG_MSG(KERN_INFO "viafb_init_lcd_size fail\n"); + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID1_800X600; + viaparinfo->lvds_setting_info->lcd_panel_size = + fp_id_to_vindex(LCD_PANEL_ID1_800X600); + } + viaparinfo->lvds_setting_info2->lcd_panel_id = + viaparinfo->lvds_setting_info->lcd_panel_id; + viaparinfo->lvds_setting_info2->lcd_panel_size = + viaparinfo->lvds_setting_info->lcd_panel_size; + viaparinfo->lvds_setting_info2->lcd_panel_hres = + viaparinfo->lvds_setting_info->lcd_panel_hres; + viaparinfo->lvds_setting_info2->lcd_panel_vres = + viaparinfo->lvds_setting_info->lcd_panel_vres; + viaparinfo->lvds_setting_info2->device_lcd_dualedge = + viaparinfo->lvds_setting_info->device_lcd_dualedge; + viaparinfo->lvds_setting_info2->LCDDithering = + viaparinfo->lvds_setting_info->LCDDithering; +} + +static bool lvds_identify_integratedlvds(void) +{ + if (viafb_display_hardware_layout == HW_LAYOUT_LCD_EXTERNAL_LCD2) { + /* Two dual channel LCD (Internal LVDS + External LVDS): */ + /* If we have an external LVDS, such as VT1636, we should + have its chip ID already. */ + if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { + viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name = + INTEGRATED_LVDS; + DEBUG_MSG(KERN_INFO "Support two dual channel LVDS!\ + (Internal LVDS + External LVDS)\n"); + } else { + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = + INTEGRATED_LVDS; + DEBUG_MSG(KERN_INFO "Not found external LVDS,\ + so can't support two dual channel LVDS!\n"); + } + } else if (viafb_display_hardware_layout == HW_LAYOUT_LCD1_LCD2) { + /* Two single channel LCD (Internal LVDS + Internal LVDS): */ + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = + INTEGRATED_LVDS; + viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name = + INTEGRATED_LVDS; + DEBUG_MSG(KERN_INFO "Support two single channel LVDS!\ + (Internal LVDS + Internal LVDS)\n"); + } else if (viafb_display_hardware_layout != HW_LAYOUT_DVI_ONLY) { + /* If we have found external LVDS, just use it, + otherwise, we will use internal LVDS as default. */ + if (!viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = + INTEGRATED_LVDS; + DEBUG_MSG(KERN_INFO "Found Integrated LVDS!\n"); + } + } else { + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = + NON_LVDS_TRANSMITTER; + DEBUG_MSG(KERN_INFO "Do not support LVDS!\n"); + return false; + } + + return true; +} + +int viafb_lvds_trasmitter_identify(void) +{ + viaparinfo->i2c_stuff.i2c_port = I2CPORTINDEX; + if (viafb_lvds_identify_vt1636()) { + viaparinfo->chip_info->lvds_chip_info.i2c_port = I2CPORTINDEX; + DEBUG_MSG(KERN_INFO + "Found VIA VT1636 LVDS on port i2c 0x31 \n"); + } else { + viaparinfo->i2c_stuff.i2c_port = GPIOPORTINDEX; + if (viafb_lvds_identify_vt1636()) { + viaparinfo->chip_info->lvds_chip_info.i2c_port = + GPIOPORTINDEX; + DEBUG_MSG(KERN_INFO + "Found VIA VT1636 LVDS on port gpio 0x2c \n"); + } + } + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) + lvds_identify_integratedlvds(); + + if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) + return true; + /* Check for VT1631: */ + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1631_LVDS; + viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = + VT1631_LVDS_I2C_ADDR; + + if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID) != FAIL) { + DEBUG_MSG(KERN_INFO "\n VT1631 LVDS ! \n"); + DEBUG_MSG(KERN_INFO "\n %2d", + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name); + DEBUG_MSG(KERN_INFO "\n %2d", + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name); + return OK; + } + + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = + NON_LVDS_TRANSMITTER; + viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = + VT1631_LVDS_I2C_ADDR; + return FAIL; +} + +static int fp_id_to_vindex(int panel_id) +{ + DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n"); + + if (panel_id > LCD_PANEL_ID_MAXIMUM) + viafb_lcd_panel_id = panel_id = + viafb_read_reg(VIACR, CR3F) & 0x0F; + + switch (panel_id) { + case 0x0: + viaparinfo->lvds_setting_info->lcd_panel_hres = 640; + viaparinfo->lvds_setting_info->lcd_panel_vres = 480; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID0_640X480; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_640X480; + break; + case 0x1: + viaparinfo->lvds_setting_info->lcd_panel_hres = 800; + viaparinfo->lvds_setting_info->lcd_panel_vres = 600; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID1_800X600; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_800X600; + break; + case 0x2: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID2_1024X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1024X768; + break; + case 0x3: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID3_1280X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1280X768; + break; + case 0x4: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; + viaparinfo->lvds_setting_info->lcd_panel_vres = 1024; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID4_1280X1024; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1280X1024; + break; + case 0x5: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1400; + viaparinfo->lvds_setting_info->lcd_panel_vres = 1050; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID5_1400X1050; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1400X1050; + break; + case 0x6: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1600; + viaparinfo->lvds_setting_info->lcd_panel_vres = 1200; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID6_1600X1200; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1600X1200; + break; + case 0x8: + viaparinfo->lvds_setting_info->lcd_panel_hres = 800; + viaparinfo->lvds_setting_info->lcd_panel_vres = 480; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_IDA_800X480; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_800X480; + break; + case 0x9: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID2_1024X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1024X768; + break; + case 0xA: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID2_1024X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1024X768; + break; + case 0xB: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID2_1024X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1024X768; + break; + case 0xC: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID3_1280X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1280X768; + break; + case 0xD: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; + viaparinfo->lvds_setting_info->lcd_panel_vres = 1024; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID4_1280X1024; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1280X1024; + break; + case 0xE: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1400; + viaparinfo->lvds_setting_info->lcd_panel_vres = 1050; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID5_1400X1050; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1400X1050; + break; + case 0xF: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1600; + viaparinfo->lvds_setting_info->lcd_panel_vres = 1200; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID6_1600X1200; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1600X1200; + break; + case 0x10: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1366; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID7_1366X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1368X768; + break; + case 0x11: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1024; + viaparinfo->lvds_setting_info->lcd_panel_vres = 600; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID8_1024X600; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1024X600; + break; + case 0x12: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID3_1280X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1280X768; + break; + case 0x13: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; + viaparinfo->lvds_setting_info->lcd_panel_vres = 800; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID9_1280X800; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_1280X800; + break; + case 0x14: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1360; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_IDB_1360X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1360X768; + break; + case 0x15: + viaparinfo->lvds_setting_info->lcd_panel_hres = 1280; + viaparinfo->lvds_setting_info->lcd_panel_vres = 768; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID3_1280X768; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 1; + viaparinfo->lvds_setting_info->LCDDithering = 0; + return VIA_RES_1280X768; + break; + case 0x16: + viaparinfo->lvds_setting_info->lcd_panel_hres = 480; + viaparinfo->lvds_setting_info->lcd_panel_vres = 640; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_IDC_480X640; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_480X640; + break; + default: + viaparinfo->lvds_setting_info->lcd_panel_hres = 800; + viaparinfo->lvds_setting_info->lcd_panel_vres = 600; + viaparinfo->lvds_setting_info->lcd_panel_id = + LCD_PANEL_ID1_800X600; + viaparinfo->lvds_setting_info->device_lcd_dualedge = 0; + viaparinfo->lvds_setting_info->LCDDithering = 1; + return VIA_RES_800X600; + } +} + +static int lvds_register_read(int index) +{ + u8 data; + + viaparinfo->i2c_stuff.i2c_port = GPIOPORTINDEX; + viafb_i2c_readbyte((u8) viaparinfo->chip_info-> + lvds_chip_info.lvds_chip_slave_addr, + (u8) index, &data); + return data; +} + +static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, + int panel_vres) +{ + int reg_value = 0; + int viafb_load_reg_num; + struct io_register *reg = NULL; + + DEBUG_MSG(KERN_INFO "load_lcd_scaling()!!\n"); + + /* LCD Scaling Enable */ + viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2); + if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) { + viafb_load_scaling_factor_for_p4m900(set_hres, set_vres, + panel_hres, panel_vres); + return; + } + + /* Check if expansion for horizontal */ + if (set_hres != panel_hres) { + /* Load Horizontal Scaling Factor */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + reg_value = + CLE266_LCD_HOR_SCF_FORMULA(set_hres, panel_hres); + viafb_load_reg_num = + lcd_scaling_factor_CLE.lcd_hor_scaling_factor. + reg_num; + reg = lcd_scaling_factor_CLE.lcd_hor_scaling_factor.reg; + viafb_load_reg(reg_value, + viafb_load_reg_num, reg, VIACR); + break; + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + case UNICHROME_CX700: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + reg_value = + K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres); + /* Horizontal scaling enabled */ + viafb_write_reg_mask(CRA2, VIACR, 0xC0, BIT7 + BIT6); + viafb_load_reg_num = + lcd_scaling_factor.lcd_hor_scaling_factor.reg_num; + reg = lcd_scaling_factor.lcd_hor_scaling_factor.reg; + viafb_load_reg(reg_value, + viafb_load_reg_num, reg, VIACR); + break; + } + + DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d", reg_value); + } else { + /* Horizontal scaling disabled */ + viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT7); + } + + /* Check if expansion for vertical */ + if (set_vres != panel_vres) { + /* Load Vertical Scaling Factor */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + reg_value = + CLE266_LCD_VER_SCF_FORMULA(set_vres, panel_vres); + viafb_load_reg_num = + lcd_scaling_factor_CLE.lcd_ver_scaling_factor. + reg_num; + reg = lcd_scaling_factor_CLE.lcd_ver_scaling_factor.reg; + viafb_load_reg(reg_value, + viafb_load_reg_num, reg, VIACR); + break; + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + case UNICHROME_CX700: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + reg_value = + K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres); + /* Vertical scaling enabled */ + viafb_write_reg_mask(CRA2, VIACR, 0x08, BIT3); + viafb_load_reg_num = + lcd_scaling_factor.lcd_ver_scaling_factor.reg_num; + reg = lcd_scaling_factor.lcd_ver_scaling_factor.reg; + viafb_load_reg(reg_value, + viafb_load_reg_num, reg, VIACR); + break; + } + + DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d", reg_value); + } else { + /* Vertical scaling disabled */ + viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT3); + } +} + +static void load_lcd_k400_patch_tbl(int set_hres, int set_vres, + int panel_id) +{ + int vmode_index; + int reg_num = 0; + struct io_reg *lcd_patch_reg = NULL; + + if (viaparinfo->lvds_setting_info->iga_path == IGA2) + vmode_index = viafb_get_mode_index(set_hres, set_vres, 1); + else + vmode_index = viafb_get_mode_index(set_hres, set_vres, 0); + switch (panel_id) { + /* LCD 800x600 */ + case LCD_PANEL_ID1_800X600: + switch (vmode_index) { + case VIA_RES_640X400: + case VIA_RES_640X480: + reg_num = NUM_TOTAL_K400_LCD_RES_6X4_8X6; + lcd_patch_reg = K400_LCD_RES_6X4_8X6; + break; + case VIA_RES_720X480: + case VIA_RES_720X576: + reg_num = NUM_TOTAL_K400_LCD_RES_7X4_8X6; + lcd_patch_reg = K400_LCD_RES_7X4_8X6; + break; + } + break; + + /* LCD 1024x768 */ + case LCD_PANEL_ID2_1024X768: + switch (vmode_index) { + case VIA_RES_640X400: + case VIA_RES_640X480: + reg_num = NUM_TOTAL_K400_LCD_RES_6X4_10X7; + lcd_patch_reg = K400_LCD_RES_6X4_10X7; + break; + case VIA_RES_720X480: + case VIA_RES_720X576: + reg_num = NUM_TOTAL_K400_LCD_RES_7X4_10X7; + lcd_patch_reg = K400_LCD_RES_7X4_10X7; + break; + case VIA_RES_800X600: + reg_num = NUM_TOTAL_K400_LCD_RES_8X6_10X7; + lcd_patch_reg = K400_LCD_RES_8X6_10X7; + break; + } + break; + + /* LCD 1280x1024 */ + case LCD_PANEL_ID4_1280X1024: + switch (vmode_index) { + case VIA_RES_640X400: + case VIA_RES_640X480: + reg_num = NUM_TOTAL_K400_LCD_RES_6X4_12X10; + lcd_patch_reg = K400_LCD_RES_6X4_12X10; + break; + case VIA_RES_720X480: + case VIA_RES_720X576: + reg_num = NUM_TOTAL_K400_LCD_RES_7X4_12X10; + lcd_patch_reg = K400_LCD_RES_7X4_12X10; + break; + case VIA_RES_800X600: + reg_num = NUM_TOTAL_K400_LCD_RES_8X6_12X10; + lcd_patch_reg = K400_LCD_RES_8X6_12X10; + break; + case VIA_RES_1024X768: + reg_num = NUM_TOTAL_K400_LCD_RES_10X7_12X10; + lcd_patch_reg = K400_LCD_RES_10X7_12X10; + break; + + } + break; + + /* LCD 1400x1050 */ + case LCD_PANEL_ID5_1400X1050: + switch (vmode_index) { + case VIA_RES_640X480: + reg_num = NUM_TOTAL_K400_LCD_RES_6X4_14X10; + lcd_patch_reg = K400_LCD_RES_6X4_14X10; + break; + case VIA_RES_800X600: + reg_num = NUM_TOTAL_K400_LCD_RES_8X6_14X10; + lcd_patch_reg = K400_LCD_RES_8X6_14X10; + break; + case VIA_RES_1024X768: + reg_num = NUM_TOTAL_K400_LCD_RES_10X7_14X10; + lcd_patch_reg = K400_LCD_RES_10X7_14X10; + break; + case VIA_RES_1280X768: + case VIA_RES_1280X800: + case VIA_RES_1280X960: + case VIA_RES_1280X1024: + reg_num = NUM_TOTAL_K400_LCD_RES_12X10_14X10; + lcd_patch_reg = K400_LCD_RES_12X10_14X10; + break; + } + break; + + /* LCD 1600x1200 */ + case LCD_PANEL_ID6_1600X1200: + switch (vmode_index) { + case VIA_RES_640X400: + case VIA_RES_640X480: + reg_num = NUM_TOTAL_K400_LCD_RES_6X4_16X12; + lcd_patch_reg = K400_LCD_RES_6X4_16X12; + break; + case VIA_RES_720X480: + case VIA_RES_720X576: + reg_num = NUM_TOTAL_K400_LCD_RES_7X4_16X12; + lcd_patch_reg = K400_LCD_RES_7X4_16X12; + break; + case VIA_RES_800X600: + reg_num = NUM_TOTAL_K400_LCD_RES_8X6_16X12; + lcd_patch_reg = K400_LCD_RES_8X6_16X12; + break; + case VIA_RES_1024X768: + reg_num = NUM_TOTAL_K400_LCD_RES_10X7_16X12; + lcd_patch_reg = K400_LCD_RES_10X7_16X12; + break; + case VIA_RES_1280X768: + case VIA_RES_1280X800: + case VIA_RES_1280X960: + case VIA_RES_1280X1024: + reg_num = NUM_TOTAL_K400_LCD_RES_12X10_16X12; + lcd_patch_reg = K400_LCD_RES_12X10_16X12; + break; + } + break; + + /* LCD 1366x768 */ + case LCD_PANEL_ID7_1366X768: + switch (vmode_index) { + case VIA_RES_640X480: + reg_num = NUM_TOTAL_K400_LCD_RES_6X4_1366X7; + lcd_patch_reg = K400_LCD_RES_6X4_1366X7; + break; + case VIA_RES_720X480: + case VIA_RES_720X576: + reg_num = NUM_TOTAL_K400_LCD_RES_7X4_1366X7; + lcd_patch_reg = K400_LCD_RES_7X4_1366X7; + break; + case VIA_RES_800X600: + reg_num = NUM_TOTAL_K400_LCD_RES_8X6_1366X7; + lcd_patch_reg = K400_LCD_RES_8X6_1366X7; + break; + case VIA_RES_1024X768: + reg_num = NUM_TOTAL_K400_LCD_RES_10X7_1366X7; + lcd_patch_reg = K400_LCD_RES_10X7_1366X7; + break; + case VIA_RES_1280X768: + case VIA_RES_1280X800: + case VIA_RES_1280X960: + case VIA_RES_1280X1024: + reg_num = NUM_TOTAL_K400_LCD_RES_12X10_1366X7; + lcd_patch_reg = K400_LCD_RES_12X10_1366X7; + break; + } + break; + + /* LCD 1360x768 */ + case LCD_PANEL_IDB_1360X768: + break; + } + if (reg_num != 0) { + /* H.W. Reset : ON */ + viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); + + viafb_write_regx(lcd_patch_reg, reg_num); + + /* H.W. Reset : OFF */ + viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); + + /* Reset PLL */ + viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1); + viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1); + + /* Fire! */ + outb(inb(VIARMisc) | (BIT2 + BIT3), VIAWMisc); + } +} + +static void load_lcd_p880_patch_tbl(int set_hres, int set_vres, + int panel_id) +{ + int vmode_index; + int reg_num = 0; + struct io_reg *lcd_patch_reg = NULL; + + if (viaparinfo->lvds_setting_info->iga_path == IGA2) + vmode_index = viafb_get_mode_index(set_hres, set_vres, 1); + else + vmode_index = viafb_get_mode_index(set_hres, set_vres, 0); + + switch (panel_id) { + case LCD_PANEL_ID5_1400X1050: + switch (vmode_index) { + case VIA_RES_640X480: + reg_num = NUM_TOTAL_P880_LCD_RES_6X4_14X10; + lcd_patch_reg = P880_LCD_RES_6X4_14X10; + break; + case VIA_RES_800X600: + reg_num = NUM_TOTAL_P880_LCD_RES_8X6_14X10; + lcd_patch_reg = P880_LCD_RES_8X6_14X10; + break; + } + break; + case LCD_PANEL_ID6_1600X1200: + switch (vmode_index) { + case VIA_RES_640X400: + case VIA_RES_640X480: + reg_num = NUM_TOTAL_P880_LCD_RES_6X4_16X12; + lcd_patch_reg = P880_LCD_RES_6X4_16X12; + break; + case VIA_RES_720X480: + case VIA_RES_720X576: + reg_num = NUM_TOTAL_P880_LCD_RES_7X4_16X12; + lcd_patch_reg = P880_LCD_RES_7X4_16X12; + break; + case VIA_RES_800X600: + reg_num = NUM_TOTAL_P880_LCD_RES_8X6_16X12; + lcd_patch_reg = P880_LCD_RES_8X6_16X12; + break; + case VIA_RES_1024X768: + reg_num = NUM_TOTAL_P880_LCD_RES_10X7_16X12; + lcd_patch_reg = P880_LCD_RES_10X7_16X12; + break; + case VIA_RES_1280X768: + case VIA_RES_1280X960: + case VIA_RES_1280X1024: + reg_num = NUM_TOTAL_P880_LCD_RES_12X10_16X12; + lcd_patch_reg = P880_LCD_RES_12X10_16X12; + break; + } + break; + + } + if (reg_num != 0) { + /* H.W. Reset : ON */ + viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); + + viafb_write_regx(lcd_patch_reg, reg_num); + + /* H.W. Reset : OFF */ + viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); + + /* Reset PLL */ + viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1); + viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1); + + /* Fire! */ + outb(inb(VIARMisc) | (BIT2 + BIT3), VIAWMisc); + } +} + +static void load_lcd_patch_regs(int set_hres, int set_vres, + int panel_id, int set_iga) +{ + int vmode_index; + + if (viaparinfo->lvds_setting_info->iga_path == IGA2) + vmode_index = viafb_get_mode_index(set_hres, set_vres, 1); + else + vmode_index = viafb_get_mode_index(set_hres, set_vres, 0); + + viafb_unlock_crt(); + + /* Patch for simultaneous & Expansion */ + if ((set_iga == IGA1_IGA2) && + (viaparinfo->lvds_setting_info->display_method == + LCD_EXPANDSION)) { + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + load_lcd_k400_patch_tbl(set_hres, set_vres, panel_id); + break; + case UNICHROME_K800: + break; + case UNICHROME_PM800: + case UNICHROME_CN700: + case UNICHROME_CX700: + load_lcd_p880_patch_tbl(set_hres, set_vres, panel_id); + } + } + + viafb_lock_crt(); +} + +static void via_pitch_alignment_patch_lcd( + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information + *plvds_chip_info) +{ + unsigned char cr13, cr35, cr65, cr66, cr67; + unsigned long dwScreenPitch = 0; + unsigned long dwPitch; + + dwPitch = plvds_setting_info->h_active * (plvds_setting_info->bpp >> 3); + if (dwPitch & 0x1F) { + dwScreenPitch = ((dwPitch + 31) & ~31) >> 3; + if (plvds_setting_info->iga_path == IGA2) { + if (plvds_setting_info->bpp > 8) { + cr66 = (unsigned char)(dwScreenPitch & 0xFF); + viafb_write_reg(CR66, VIACR, cr66); + cr67 = viafb_read_reg(VIACR, CR67) & 0xFC; + cr67 |= + (unsigned + char)((dwScreenPitch & 0x300) >> 8); + viafb_write_reg(CR67, VIACR, cr67); + } + + /* Fetch Count */ + cr67 = viafb_read_reg(VIACR, CR67) & 0xF3; + cr67 |= (unsigned char)((dwScreenPitch & 0x600) >> 7); + viafb_write_reg(CR67, VIACR, cr67); + cr65 = (unsigned char)((dwScreenPitch >> 1) & 0xFF); + cr65 += 2; + viafb_write_reg(CR65, VIACR, cr65); + } else { + if (plvds_setting_info->bpp > 8) { + cr13 = (unsigned char)(dwScreenPitch & 0xFF); + viafb_write_reg(CR13, VIACR, cr13); + cr35 = viafb_read_reg(VIACR, CR35) & 0x1F; + cr35 |= + (unsigned + char)((dwScreenPitch & 0x700) >> 3); + viafb_write_reg(CR35, VIACR, cr35); + } + } + } +} +static void lcd_patch_skew_dvp0(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) { + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_P4M900: + viafb_vt1636_patch_skew_on_vt3364(plvds_setting_info, + plvds_chip_info); + break; + case UNICHROME_P4M890: + viafb_vt1636_patch_skew_on_vt3327(plvds_setting_info, + plvds_chip_info); + break; + } + } +} +static void lcd_patch_skew_dvp1(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) { + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CX700: + viafb_vt1636_patch_skew_on_vt3324(plvds_setting_info, + plvds_chip_info); + break; + } + } +} +static void lcd_patch_skew(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information *plvds_chip_info) +{ + DEBUG_MSG(KERN_INFO "lcd_patch_skew\n"); + switch (plvds_chip_info->output_interface) { + case INTERFACE_DVP0: + lcd_patch_skew_dvp0(plvds_setting_info, plvds_chip_info); + break; + case INTERFACE_DVP1: + lcd_patch_skew_dvp1(plvds_setting_info, plvds_chip_info); + break; + case INTERFACE_DFP_LOW: + if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) { + viafb_write_reg_mask(CR99, VIACR, 0x08, + BIT0 + BIT1 + BIT2 + BIT3); + } + break; + } +} + +/* LCD Set Mode */ +void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + int video_index = plvds_setting_info->lcd_panel_size; + int set_iga = plvds_setting_info->iga_path; + int mode_bpp = plvds_setting_info->bpp; + int viafb_load_reg_num = 0; + int reg_value = 0; + int set_hres, set_vres; + int panel_hres, panel_vres; + u32 pll_D_N; + int offset; + struct io_register *reg = NULL; + struct display_timing mode_crt_reg, panel_crt_reg; + struct crt_mode_table *panel_crt_table = NULL; + struct VideoModeTable *vmode_tbl = NULL; + + DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n"); + /* Get mode table */ + mode_crt_reg = mode_crt_table->crtc; + /* Get panel table Pointer */ + vmode_tbl = viafb_get_modetbl_pointer(video_index); + panel_crt_table = vmode_tbl->crtc; + panel_crt_reg = panel_crt_table->crtc; + DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n"); + set_hres = plvds_setting_info->h_active; + set_vres = plvds_setting_info->v_active; + panel_hres = plvds_setting_info->lcd_panel_hres; + panel_vres = plvds_setting_info->lcd_panel_vres; + if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) + viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info); + plvds_setting_info->vclk = panel_crt_table->clk; + if (set_iga == IGA1) { + /* IGA1 doesn't have LCD scaling, so set it as centering. */ + viafb_load_crtc_timing(lcd_centering_timging + (mode_crt_reg, panel_crt_reg), IGA1); + } else { + /* Expansion */ + if ((plvds_setting_info->display_method == + LCD_EXPANDSION) & ((set_hres != panel_hres) + || (set_vres != panel_vres))) { + /* expansion timing IGA2 loaded panel set timing*/ + viafb_load_crtc_timing(panel_crt_reg, IGA2); + DEBUG_MSG(KERN_INFO "viafb_load_crtc_timing!!\n"); + load_lcd_scaling(set_hres, set_vres, panel_hres, + panel_vres); + DEBUG_MSG(KERN_INFO "load_lcd_scaling!!\n"); + } else { /* Centering */ + /* centering timing IGA2 always loaded panel + and mode releative timing */ + viafb_load_crtc_timing(lcd_centering_timging + (mode_crt_reg, panel_crt_reg), IGA2); + viafb_write_reg_mask(CR79, VIACR, 0x00, + BIT0 + BIT1 + BIT2); + /* LCD scaling disabled */ + } + } + + if (set_iga == IGA1_IGA2) { + load_crtc_shadow_timing(mode_crt_reg, panel_crt_reg); + /* Fill shadow registers */ + + switch (plvds_setting_info->lcd_panel_id) { + case LCD_PANEL_ID0_640X480: + offset = 80; + break; + case LCD_PANEL_ID1_800X600: + case LCD_PANEL_IDA_800X480: + offset = 110; + break; + case LCD_PANEL_ID2_1024X768: + offset = 150; + break; + case LCD_PANEL_ID3_1280X768: + case LCD_PANEL_ID4_1280X1024: + case LCD_PANEL_ID5_1400X1050: + case LCD_PANEL_ID9_1280X800: + offset = 190; + break; + case LCD_PANEL_ID6_1600X1200: + offset = 250; + break; + case LCD_PANEL_ID7_1366X768: + case LCD_PANEL_IDB_1360X768: + offset = 212; + break; + default: + offset = 140; + break; + } + + /* Offset for simultaneous */ + reg_value = offset; + viafb_load_reg_num = offset_reg.iga2_offset_reg.reg_num; + reg = offset_reg.iga2_offset_reg.reg; + viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); + DEBUG_MSG(KERN_INFO "viafb_load_reg!!\n"); + viafb_load_fetch_count_reg(set_hres, 4, IGA2); + /* Fetch count for simultaneous */ + } else { /* SAMM */ + /* Offset for IGA2 only */ + viafb_load_offset_reg(set_hres, mode_bpp / 8, set_iga); + /* Fetch count for IGA2 only */ + viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga); + + if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) + && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400)) + viafb_load_FIFO_reg(set_iga, set_hres, set_vres); + + viafb_set_color_depth(mode_bpp / 8, set_iga); + } + + fill_lcd_format(); + + pll_D_N = viafb_get_clk_value(panel_crt_table[0].clk); + DEBUG_MSG(KERN_INFO "PLL=0x%x", pll_D_N); + viafb_set_vclock(pll_D_N, set_iga); + + viafb_set_output_path(DEVICE_LCD, set_iga, + plvds_chip_info->output_interface); + lcd_patch_skew(plvds_setting_info, plvds_chip_info); + + /* If K8M800, enable LCD Prefetch Mode. */ + if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) + || (UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)) + viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0); + + load_lcd_patch_regs(set_hres, set_vres, + plvds_setting_info->lcd_panel_id, set_iga); + + DEBUG_MSG(KERN_INFO "load_lcd_patch_regs!!\n"); + + /* Patch for non 32bit alignment mode */ + via_pitch_alignment_patch_lcd(plvds_setting_info, plvds_chip_info); +} + +static void integrated_lvds_disable(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + bool turn_off_first_powersequence = false; + bool turn_off_second_powersequence = false; + if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface) + turn_off_first_powersequence = true; + if (INTERFACE_LVDS0 == plvds_chip_info->output_interface) + turn_off_first_powersequence = true; + if (INTERFACE_LVDS1 == plvds_chip_info->output_interface) + turn_off_second_powersequence = true; + if (turn_off_second_powersequence) { + /* Use second power sequence control: */ + + /* Turn off power sequence. */ + viafb_write_reg_mask(CRD4, VIACR, 0, BIT1); + + /* Turn off back light. */ + viafb_write_reg_mask(CRD3, VIACR, 0xC0, BIT6 + BIT7); + } + if (turn_off_first_powersequence) { + /* Use first power sequence control: */ + + /* Turn off power sequence. */ + viafb_write_reg_mask(CR6A, VIACR, 0, BIT3); + + /* Turn off back light. */ + viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7); + } + + /* Turn DFP High/Low Pad off. */ + viafb_write_reg_mask(SR2A, VIASR, 0, BIT0 + BIT1 + BIT2 + BIT3); + + /* Power off LVDS channel. */ + switch (plvds_chip_info->output_interface) { + case INTERFACE_LVDS0: + { + viafb_write_reg_mask(CRD2, VIACR, 0x80, BIT7); + break; + } + + case INTERFACE_LVDS1: + { + viafb_write_reg_mask(CRD2, VIACR, 0x40, BIT6); + break; + } + + case INTERFACE_LVDS0LVDS1: + { + viafb_write_reg_mask(CRD2, VIACR, 0xC0, BIT6 + BIT7); + break; + } + } +} + +static void integrated_lvds_enable(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + bool turn_on_first_powersequence = false; + bool turn_on_second_powersequence = false; + + DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n", + plvds_chip_info->output_interface); + if (plvds_setting_info->lcd_mode == LCD_SPWG) + viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1); + else + viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1); + if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface) + turn_on_first_powersequence = true; + if (INTERFACE_LVDS0 == plvds_chip_info->output_interface) + turn_on_first_powersequence = true; + if (INTERFACE_LVDS1 == plvds_chip_info->output_interface) + turn_on_second_powersequence = true; + + if (turn_on_second_powersequence) { + /* Use second power sequence control: */ + + /* Use hardware control power sequence. */ + viafb_write_reg_mask(CRD3, VIACR, 0, BIT0); + + /* Turn on back light. */ + viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7); + + /* Turn on hardware power sequence. */ + viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); + } + if (turn_on_first_powersequence) { + /* Use first power sequence control: */ + + /* Use hardware control power sequence. */ + viafb_write_reg_mask(CR91, VIACR, 0, BIT0); + + /* Turn on back light. */ + viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7); + + /* Turn on hardware power sequence. */ + viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); + } + + /* Turn DFP High/Low pad on. */ + viafb_write_reg_mask(SR2A, VIASR, 0x0F, BIT0 + BIT1 + BIT2 + BIT3); + + /* Power on LVDS channel. */ + switch (plvds_chip_info->output_interface) { + case INTERFACE_LVDS0: + { + viafb_write_reg_mask(CRD2, VIACR, 0, BIT7); + break; + } + + case INTERFACE_LVDS1: + { + viafb_write_reg_mask(CRD2, VIACR, 0, BIT6); + break; + } + + case INTERFACE_LVDS0LVDS1: + { + viafb_write_reg_mask(CRD2, VIACR, 0, BIT6 + BIT7); + break; + } + } +} + +void viafb_lcd_disable(void) +{ + + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { + lcd_powersequence_off(); + /* DI1 pad off */ + viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30); + } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { + if (viafb_LCD2_ON + && (INTEGRATED_LVDS == + viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name)) + integrated_lvds_disable(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info2); + if (INTEGRATED_LVDS == + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) + integrated_lvds_disable(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); + if (VT1636_LVDS == viaparinfo->chip_info-> + lvds_chip_info.lvds_chip_name) + viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); + } else if (VT1636_LVDS == + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { + viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); + } else { + /* DFP-HL pad off */ + viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0F); + /* Backlight off */ + viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20); + /* 24 bit DI data paht off */ + viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80); + /* Simultaneout disabled */ + viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08); + } + + /* Disable expansion bit */ + viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01); + /* CRT path set to IGA1 */ + viafb_write_reg_mask(SR16, VIASR, 0x00, 0x40); + /* Simultaneout disabled */ + viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08); + /* IGA2 path disabled */ + viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80); + +} + +void viafb_lcd_enable(void) +{ + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { + /* DI1 pad on */ + viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30); + lcd_powersequence_on(); + } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) { + if (viafb_LCD2_ON && (INTEGRATED_LVDS == + viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name)) + integrated_lvds_enable(viaparinfo->lvds_setting_info2, \ + &viaparinfo->chip_info->lvds_chip_info2); + if (INTEGRATED_LVDS == + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) + integrated_lvds_enable(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); + if (VT1636_LVDS == viaparinfo->chip_info-> + lvds_chip_info.lvds_chip_name) + viafb_enable_lvds_vt1636(viaparinfo-> + lvds_setting_info, &viaparinfo->chip_info-> + lvds_chip_info); + } else if (VT1636_LVDS == + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { + viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); + } else { + /* DFP-HL pad on */ + viafb_write_reg_mask(SR2A, VIASR, 0x0F, 0x0F); + /* Backlight on */ + viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20); + /* 24 bit DI data paht on */ + viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80); + + /* Set data source selection bit by iga path */ + if (viaparinfo->lvds_setting_info->iga_path == IGA1) { + /* DFP-H set to IGA1 */ + viafb_write_reg_mask(CR97, VIACR, 0x00, 0x10); + /* DFP-L set to IGA1 */ + viafb_write_reg_mask(CR99, VIACR, 0x00, 0x10); + } else { + /* DFP-H set to IGA2 */ + viafb_write_reg_mask(CR97, VIACR, 0x10, 0x10); + /* DFP-L set to IGA2 */ + viafb_write_reg_mask(CR99, VIACR, 0x10, 0x10); + } + /* LCD enabled */ + viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48); + } + + if ((viaparinfo->lvds_setting_info->iga_path == IGA1) + || (viaparinfo->lvds_setting_info->iga_path == IGA1_IGA2)) { + /* CRT path set to IGA2 */ + viafb_write_reg_mask(SR16, VIASR, 0x40, 0x40); + /* IGA2 path disabled */ + viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80); + /* IGA2 path enabled */ + } else { /* IGA2 */ + viafb_write_reg_mask(CR6A, VIACR, 0x80, 0x80); + } + +} + +static void lcd_powersequence_off(void) +{ + int i, mask, data; + + /* Software control power sequence */ + viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11); + + for (i = 0; i < 3; i++) { + mask = PowerSequenceOff[0][i]; + data = PowerSequenceOff[1][i] & mask; + viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask); + udelay(PowerSequenceOff[2][i]); + } + + /* Disable LCD */ + viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x08); +} + +static void lcd_powersequence_on(void) +{ + int i, mask, data; + + /* Software control power sequence */ + viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11); + + /* Enable LCD */ + viafb_write_reg_mask(CR6A, VIACR, 0x08, 0x08); + + for (i = 0; i < 3; i++) { + mask = PowerSequenceOn[0][i]; + data = PowerSequenceOn[1][i] & mask; + viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask); + udelay(PowerSequenceOn[2][i]); + } + + udelay(1); +} + +static void fill_lcd_format(void) +{ + u8 bdithering = 0, bdual = 0; + + if (viaparinfo->lvds_setting_info->device_lcd_dualedge) + bdual = BIT4; + if (viaparinfo->lvds_setting_info->LCDDithering) + bdithering = BIT0; + /* Dual & Dithering */ + viafb_write_reg_mask(CR88, VIACR, (bdithering | bdual), BIT4 + BIT0); +} + +static void check_diport_of_integrated_lvds( + struct lvds_chip_information *plvds_chip_info, + struct lvds_setting_information + *plvds_setting_info) +{ + /* Determine LCD DI Port by hardware layout. */ + switch (viafb_display_hardware_layout) { + case HW_LAYOUT_LCD_ONLY: + { + if (plvds_setting_info->device_lcd_dualedge) { + plvds_chip_info->output_interface = + INTERFACE_LVDS0LVDS1; + } else { + plvds_chip_info->output_interface = + INTERFACE_LVDS0; + } + + break; + } + + case HW_LAYOUT_DVI_ONLY: + { + plvds_chip_info->output_interface = INTERFACE_NONE; + break; + } + + case HW_LAYOUT_LCD1_LCD2: + case HW_LAYOUT_LCD_EXTERNAL_LCD2: + { + plvds_chip_info->output_interface = + INTERFACE_LVDS0LVDS1; + break; + } + + case HW_LAYOUT_LCD_DVI: + { + plvds_chip_info->output_interface = INTERFACE_LVDS1; + break; + } + + default: + { + plvds_chip_info->output_interface = INTERFACE_LVDS1; + break; + } + } + + DEBUG_MSG(KERN_INFO + "Display Hardware Layout: 0x%x, LCD DI Port: 0x%x\n", + viafb_display_hardware_layout, + plvds_chip_info->output_interface); +} + +void viafb_init_lvds_output_interface(struct lvds_chip_information + *plvds_chip_info, + struct lvds_setting_information + *plvds_setting_info) +{ + if (INTERFACE_NONE != plvds_chip_info->output_interface) { + /*Do nothing, lcd port is specified by module parameter */ + return; + } + + switch (plvds_chip_info->lvds_chip_name) { + + case VT1636_LVDS: + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CX700: + plvds_chip_info->output_interface = INTERFACE_DVP1; + break; + case UNICHROME_CN700: + plvds_chip_info->output_interface = INTERFACE_DFP_LOW; + break; + default: + plvds_chip_info->output_interface = INTERFACE_DVP0; + break; + } + break; + + case INTEGRATED_LVDS: + check_diport_of_integrated_lvds(plvds_chip_info, + plvds_setting_info); + break; + + default: + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + case UNICHROME_P4M900: + case UNICHROME_P4M890: + plvds_chip_info->output_interface = INTERFACE_DFP_LOW; + break; + default: + plvds_chip_info->output_interface = INTERFACE_DFP; + break; + } + break; + } +} + +static struct display_timing lcd_centering_timging(struct display_timing + mode_crt_reg, + struct display_timing panel_crt_reg) +{ + struct display_timing crt_reg; + + crt_reg.hor_total = panel_crt_reg.hor_total; + crt_reg.hor_addr = mode_crt_reg.hor_addr; + crt_reg.hor_blank_start = + (panel_crt_reg.hor_addr - mode_crt_reg.hor_addr) / 2 + + crt_reg.hor_addr; + crt_reg.hor_blank_end = panel_crt_reg.hor_blank_end; + crt_reg.hor_sync_start = + (panel_crt_reg.hor_sync_start - + panel_crt_reg.hor_blank_start) + crt_reg.hor_blank_start; + crt_reg.hor_sync_end = panel_crt_reg.hor_sync_end; + + crt_reg.ver_total = panel_crt_reg.ver_total; + crt_reg.ver_addr = mode_crt_reg.ver_addr; + crt_reg.ver_blank_start = + (panel_crt_reg.ver_addr - mode_crt_reg.ver_addr) / 2 + + crt_reg.ver_addr; + crt_reg.ver_blank_end = panel_crt_reg.ver_blank_end; + crt_reg.ver_sync_start = + (panel_crt_reg.ver_sync_start - + panel_crt_reg.ver_blank_start) + crt_reg.ver_blank_start; + crt_reg.ver_sync_end = panel_crt_reg.ver_sync_end; + + return crt_reg; +} + +static void load_crtc_shadow_timing(struct display_timing mode_timing, + struct display_timing panel_timing) +{ + struct io_register *reg = NULL; + int i; + int viafb_load_reg_Num = 0; + int reg_value = 0; + + if (viaparinfo->lvds_setting_info->display_method == LCD_EXPANDSION) { + /* Expansion */ + for (i = 12; i < 20; i++) { + switch (i) { + case H_TOTAL_SHADOW_INDEX: + reg_value = + IGA2_HOR_TOTAL_SHADOW_FORMULA + (panel_timing.hor_total); + viafb_load_reg_Num = + iga2_shadow_crtc_reg.hor_total_shadow. + reg_num; + reg = iga2_shadow_crtc_reg.hor_total_shadow.reg; + break; + case H_BLANK_END_SHADOW_INDEX: + reg_value = + IGA2_HOR_BLANK_END_SHADOW_FORMULA + (panel_timing.hor_blank_start, + panel_timing.hor_blank_end); + viafb_load_reg_Num = + iga2_shadow_crtc_reg. + hor_blank_end_shadow.reg_num; + reg = + iga2_shadow_crtc_reg. + hor_blank_end_shadow.reg; + break; + case V_TOTAL_SHADOW_INDEX: + reg_value = + IGA2_VER_TOTAL_SHADOW_FORMULA + (panel_timing.ver_total); + viafb_load_reg_Num = + iga2_shadow_crtc_reg.ver_total_shadow. + reg_num; + reg = iga2_shadow_crtc_reg.ver_total_shadow.reg; + break; + case V_ADDR_SHADOW_INDEX: + reg_value = + IGA2_VER_ADDR_SHADOW_FORMULA + (panel_timing.ver_addr); + viafb_load_reg_Num = + iga2_shadow_crtc_reg.ver_addr_shadow. + reg_num; + reg = iga2_shadow_crtc_reg.ver_addr_shadow.reg; + break; + case V_BLANK_SATRT_SHADOW_INDEX: + reg_value = + IGA2_VER_BLANK_START_SHADOW_FORMULA + (panel_timing.ver_blank_start); + viafb_load_reg_Num = + iga2_shadow_crtc_reg. + ver_blank_start_shadow.reg_num; + reg = + iga2_shadow_crtc_reg. + ver_blank_start_shadow.reg; + break; + case V_BLANK_END_SHADOW_INDEX: + reg_value = + IGA2_VER_BLANK_END_SHADOW_FORMULA + (panel_timing.ver_blank_start, + panel_timing.ver_blank_end); + viafb_load_reg_Num = + iga2_shadow_crtc_reg. + ver_blank_end_shadow.reg_num; + reg = + iga2_shadow_crtc_reg. + ver_blank_end_shadow.reg; + break; + case V_SYNC_SATRT_SHADOW_INDEX: + reg_value = + IGA2_VER_SYNC_START_SHADOW_FORMULA + (panel_timing.ver_sync_start); + viafb_load_reg_Num = + iga2_shadow_crtc_reg. + ver_sync_start_shadow.reg_num; + reg = + iga2_shadow_crtc_reg. + ver_sync_start_shadow.reg; + break; + case V_SYNC_END_SHADOW_INDEX: + reg_value = + IGA2_VER_SYNC_END_SHADOW_FORMULA + (panel_timing.ver_sync_start, + panel_timing.ver_sync_end); + viafb_load_reg_Num = + iga2_shadow_crtc_reg. + ver_sync_end_shadow.reg_num; + reg = + iga2_shadow_crtc_reg. + ver_sync_end_shadow.reg; + break; + } + viafb_load_reg(reg_value, + viafb_load_reg_Num, reg, VIACR); + } + } else { /* Centering */ + for (i = 12; i < 20; i++) { + switch (i) { + case H_TOTAL_SHADOW_INDEX: + reg_value = + IGA2_HOR_TOTAL_SHADOW_FORMULA + (panel_timing.hor_total); + viafb_load_reg_Num = + iga2_shadow_crtc_reg.hor_total_shadow. + reg_num; + reg = iga2_shadow_crtc_reg.hor_total_shadow.reg; + break; + case H_BLANK_END_SHADOW_INDEX: + reg_value = + IGA2_HOR_BLANK_END_SHADOW_FORMULA + (panel_timing.hor_blank_start, + panel_timing.hor_blank_end); + viafb_load_reg_Num = + iga2_shadow_crtc_reg. + hor_blank_end_shadow.reg_num; + reg = + iga2_shadow_crtc_reg. + hor_blank_end_shadow.reg; + break; + case V_TOTAL_SHADOW_INDEX: + reg_value = + IGA2_VER_TOTAL_SHADOW_FORMULA + (panel_timing.ver_total); + viafb_load_reg_Num = + iga2_shadow_crtc_reg.ver_total_shadow. + reg_num; + reg = iga2_shadow_crtc_reg.ver_total_shadow.reg; + break; + case V_ADDR_SHADOW_INDEX: + reg_value = + IGA2_VER_ADDR_SHADOW_FORMULA + (mode_timing.ver_addr); + viafb_load_reg_Num = + iga2_shadow_crtc_reg.ver_addr_shadow. + reg_num; + reg = iga2_shadow_crtc_reg.ver_addr_shadow.reg; + break; + case V_BLANK_SATRT_SHADOW_INDEX: + reg_value = + IGA2_VER_BLANK_START_SHADOW_FORMULA + (mode_timing.ver_blank_start); + viafb_load_reg_Num = + iga2_shadow_crtc_reg. + ver_blank_start_shadow.reg_num; + reg = + iga2_shadow_crtc_reg. + ver_blank_start_shadow.reg; + break; + case V_BLANK_END_SHADOW_INDEX: + reg_value = + IGA2_VER_BLANK_END_SHADOW_FORMULA + (panel_timing.ver_blank_start, + panel_timing.ver_blank_end); + viafb_load_reg_Num = + iga2_shadow_crtc_reg. + ver_blank_end_shadow.reg_num; + reg = + iga2_shadow_crtc_reg. + ver_blank_end_shadow.reg; + break; + case V_SYNC_SATRT_SHADOW_INDEX: + reg_value = + IGA2_VER_SYNC_START_SHADOW_FORMULA( + (panel_timing.ver_sync_start - + panel_timing.ver_blank_start) + + (panel_timing.ver_addr - + mode_timing.ver_addr) / 2 + + mode_timing.ver_addr); + viafb_load_reg_Num = + iga2_shadow_crtc_reg.ver_sync_start_shadow. + reg_num; + reg = + iga2_shadow_crtc_reg.ver_sync_start_shadow. + reg; + break; + case V_SYNC_END_SHADOW_INDEX: + reg_value = + IGA2_VER_SYNC_END_SHADOW_FORMULA( + (panel_timing.ver_sync_start - + panel_timing.ver_blank_start) + + (panel_timing.ver_addr - + mode_timing.ver_addr) / 2 + + mode_timing.ver_addr, + panel_timing.ver_sync_end); + viafb_load_reg_Num = + iga2_shadow_crtc_reg.ver_sync_end_shadow. + reg_num; + reg = + iga2_shadow_crtc_reg.ver_sync_end_shadow. + reg; + break; + } + viafb_load_reg(reg_value, + viafb_load_reg_Num, reg, VIACR); + } + } +} + +bool viafb_lcd_get_mobile_state(bool *mobile) +{ + unsigned char *romptr, *tableptr; + u8 core_base; + unsigned char *biosptr; + /* Rom address */ + u32 romaddr = 0x000C0000; + u16 start_pattern = 0; + + biosptr = ioremap(romaddr, 0x10000); + + memcpy(&start_pattern, biosptr, 2); + /* Compare pattern */ + if (start_pattern == 0xAA55) { + /* Get the start of Table */ + /* 0x1B means BIOS offset position */ + romptr = biosptr + 0x1B; + tableptr = biosptr + *((u16 *) romptr); + + /* Get the start of biosver structure */ + /* 18 means BIOS version position. */ + romptr = tableptr + 18; + romptr = biosptr + *((u16 *) romptr); + + /* The offset should be 44, but the + actual image is less three char. */ + /* pRom += 44; */ + romptr += 41; + + core_base = *romptr++; + + if (core_base & 0x8) + *mobile = false; + else + *mobile = true; + /* release memory */ + iounmap(biosptr); + + return true; + } else { + iounmap(biosptr); + return false; + } +} + +static void viafb_load_scaling_factor_for_p4m900(int set_hres, + int set_vres, int panel_hres, int panel_vres) +{ + int h_scaling_factor; + int v_scaling_factor; + u8 cra2 = 0; + u8 cr77 = 0; + u8 cr78 = 0; + u8 cr79 = 0; + u8 cr9f = 0; + /* Check if expansion for horizontal */ + if (set_hres < panel_hres) { + /* Load Horizontal Scaling Factor */ + + /* For VIA_K8M800 or later chipsets. */ + h_scaling_factor = + K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres); + /* HSCaleFactor[1:0] at CR9F[1:0] */ + cr9f = h_scaling_factor & 0x0003; + /* HSCaleFactor[9:2] at CR77[7:0] */ + cr77 = (h_scaling_factor & 0x03FC) >> 2; + /* HSCaleFactor[11:10] at CR79[5:4] */ + cr79 = (h_scaling_factor & 0x0C00) >> 10; + cr79 <<= 4; + + /* Horizontal scaling enabled */ + cra2 = 0xC0; + + DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d\n", + h_scaling_factor); + } else { + /* Horizontal scaling disabled */ + cra2 = 0x00; + } + + /* Check if expansion for vertical */ + if (set_vres < panel_vres) { + /* Load Vertical Scaling Factor */ + + /* For VIA_K8M800 or later chipsets. */ + v_scaling_factor = + K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres); + + /* Vertical scaling enabled */ + cra2 |= 0x08; + /* VSCaleFactor[0] at CR79[3] */ + cr79 |= ((v_scaling_factor & 0x0001) << 3); + /* VSCaleFactor[8:1] at CR78[7:0] */ + cr78 |= (v_scaling_factor & 0x01FE) >> 1; + /* VSCaleFactor[10:9] at CR79[7:6] */ + cr79 |= ((v_scaling_factor & 0x0600) >> 9) << 6; + + DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d\n", + v_scaling_factor); + } else { + /* Vertical scaling disabled */ + cra2 |= 0x00; + } + + viafb_write_reg_mask(CRA2, VIACR, cra2, BIT3 + BIT6 + BIT7); + viafb_write_reg_mask(CR77, VIACR, cr77, 0xFF); + viafb_write_reg_mask(CR78, VIACR, cr78, 0xFF); + viafb_write_reg_mask(CR79, VIACR, cr79, 0xF8); + viafb_write_reg_mask(CR9F, VIACR, cr9f, BIT0 + BIT1); +} diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h new file mode 100644 index 00000000000..071f47cf5be --- /dev/null +++ b/drivers/video/via/lcd.h @@ -0,0 +1,94 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __LCD_H__ +#define __LCD_H__ + +/*Definition TMDS Device ID register*/ +#define VT1631_DEVICE_ID_REG 0x02 +#define VT1631_DEVICE_ID 0x92 + +#define VT3271_DEVICE_ID_REG 0x02 +#define VT3271_DEVICE_ID 0x71 + +#define GET_LCD_SIZE_BY_SYSTEM_BIOS 0x01 +#define GET_LCD_SIZE_BY_VGA_BIOS 0x02 +#define GET_LCD_SZIE_BY_HW_STRAPPING 0x03 +#define GET_LCD_SIZE_BY_USER_SETTING 0x04 + +/* Definition DVI Panel ID*/ +/* Resolution: 640x480, Channel: single, Dithering: Enable */ +#define LCD_PANEL_ID0_640X480 0x00 +/* Resolution: 800x600, Channel: single, Dithering: Enable */ +#define LCD_PANEL_ID1_800X600 0x01 +/* Resolution: 1024x768, Channel: single, Dithering: Enable */ +#define LCD_PANEL_ID2_1024X768 0x02 +/* Resolution: 1280x768, Channel: single, Dithering: Enable */ +#define LCD_PANEL_ID3_1280X768 0x03 +/* Resolution: 1280x1024, Channel: dual, Dithering: Enable */ +#define LCD_PANEL_ID4_1280X1024 0x04 +/* Resolution: 1400x1050, Channel: dual, Dithering: Enable */ +#define LCD_PANEL_ID5_1400X1050 0x05 +/* Resolution: 1600x1200, Channel: dual, Dithering: Enable */ +#define LCD_PANEL_ID6_1600X1200 0x06 +/* Resolution: 1366x768, Channel: single, Dithering: Disable */ +#define LCD_PANEL_ID7_1366X768 0x07 +/* Resolution: 1024x600, Channel: single, Dithering: Enable*/ +#define LCD_PANEL_ID8_1024X600 0x08 +/* Resolution: 1280x800, Channel: single, Dithering: Enable*/ +#define LCD_PANEL_ID9_1280X800 0x09 +/* Resolution: 800x480, Channel: single, Dithering: Enable*/ +#define LCD_PANEL_IDA_800X480 0x0A +/* Resolution: 1360x768, Channel: single, Dithering: Disable*/ +#define LCD_PANEL_IDB_1360X768 0x0B +/* Resolution: 480x640, Channel: single, Dithering: Enable */ +#define LCD_PANEL_IDC_480X640 0x0C + + +extern int viafb_LCD2_ON; +extern int viafb_LCD_ON; +extern int viafb_DVI_ON; + +void viafb_disable_lvds_vt1636(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +void viafb_enable_lvds_vt1636(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +void viafb_lcd_disable(void); +void viafb_lcd_enable(void); +void viafb_init_lcd_size(void); +void viafb_init_lvds_output_interface(struct lvds_chip_information + *plvds_chip_info, + struct lvds_setting_information + *plvds_setting_info); +void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +int viafb_lvds_trasmitter_identify(void); +void viafb_init_lvds_output_interface(struct lvds_chip_information + *plvds_chip_info, + struct lvds_setting_information + *plvds_setting_info); +bool viafb_lcd_get_mobile_state(bool *mobile); +void viafb_load_crtc_timing(struct display_timing device_timing, + int set_iga); + +#endif /* __LCD_H__ */ diff --git a/drivers/video/via/lcdtbl.h b/drivers/video/via/lcdtbl.h new file mode 100644 index 00000000000..6f3dd800be5 --- /dev/null +++ b/drivers/video/via/lcdtbl.h @@ -0,0 +1,591 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __LCDTBL_H__ +#define __LCDTBL_H__ + +#include "share.h" + +/* CLE266 Software Power Sequence */ +/* {Mask}, {Data}, {Delay} */ +int PowerSequenceOn[3][3] = + { {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, {0x19, 0x1FE, 0x01} }; +int PowerSequenceOff[3][3] = + { {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, {0xD2, 0x19, 0x01} }; + +/* ++++++ P880 ++++++ */ +/* Panel 1600x1200 */ +struct io_reg P880_LCD_RES_6X4_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x5E}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xD6}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR44, 0xFF, 0x7D}, {VIASR, SR45, 0xFF, 0x8C}, + {VIASR, SR46, 0xFF, 0x02} + +}; + +#define NUM_TOTAL_P880_LCD_RES_6X4_16X12 ARRAY_SIZE(P880_LCD_RES_6X4_16X12) + +struct io_reg P880_LCD_RES_7X4_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x78}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR44, 0xFF, 0x78}, {VIASR, SR45, 0xFF, 0x8C}, + {VIASR, SR46, 0xFF, 0x01} + +}; + +#define NUM_TOTAL_P880_LCD_RES_7X4_16X12 ARRAY_SIZE(P880_LCD_RES_7X4_16X12) + +struct io_reg P880_LCD_RES_8X6_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x83}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR44, 0xFF, 0x6D}, {VIASR, SR45, 0xFF, 0x88}, + {VIASR, SR46, 0xFF, 0x03} + +}; + +#define NUM_TOTAL_P880_LCD_RES_8X6_16X12 ARRAY_SIZE(P880_LCD_RES_8X6_16X12) + +struct io_reg P880_LCD_RES_10X7_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xAF}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR44, 0xFF, 0x92}, {VIASR, SR45, 0xFF, 0x88}, + {VIASR, SR46, 0xFF, 0x03} + +}; + +#define NUM_TOTAL_P880_LCD_RES_10X7_16X12 ARRAY_SIZE(P880_LCD_RES_10X7_16X12) + +struct io_reg P880_LCD_RES_12X10_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xD4}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR44, 0xFF, 0xF6}, {VIASR, SR45, 0xFF, 0x88}, + {VIASR, SR46, 0xFF, 0x05} + +}; + +#define NUM_TOTAL_P880_LCD_RES_12X10_16X12 ARRAY_SIZE(P880_LCD_RES_12X10_16X12) + +/* Panel 1400x1050 */ +struct io_reg P880_LCD_RES_6X4_14X10[] = { + /* 640x480 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, + {VIACR, CR5D, 0x40, 0x24}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x63}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00}, + /* VCLK */ + {VIASR, SR44, 0xFF, 0xC6}, {VIASR, SR45, 0xFF, 0x8C}, + {VIASR, SR46, 0xFF, 0x05} +}; + +#define NUM_TOTAL_P880_LCD_RES_6X4_14X10 ARRAY_SIZE(P880_LCD_RES_6X4_14X10) + +struct io_reg P880_LCD_RES_8X6_14X10[] = { + /* 800x600 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, + {VIACR, CR5D, 0x40, 0x24}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x83}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00}, + /* VCLK */ + {VIASR, SR44, 0xFF, 0x06}, {VIASR, SR45, 0xFF, 0x8D}, + {VIASR, SR46, 0xFF, 0x05} +}; + +#define NUM_TOTAL_P880_LCD_RES_8X6_14X10 ARRAY_SIZE(P880_LCD_RES_8X6_14X10) + +/* ++++++ K400 ++++++ */ +/* Panel 1600x1200 */ +struct io_reg K400_LCD_RES_6X4_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x5E}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xDA}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x7F} +}; + +#define NUM_TOTAL_K400_LCD_RES_6X4_16X12 ARRAY_SIZE(K400_LCD_RES_6X4_16X12) + +struct io_reg K400_LCD_RES_7X4_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x78}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x46}, {VIASR, SR47, 0xFF, 0x3D} +}; + +#define NUM_TOTAL_K400_LCD_RES_7X4_16X12 ARRAY_SIZE(K400_LCD_RES_7X4_16X12) + +struct io_reg K400_LCD_RES_8X6_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x83}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x85}, {VIASR, SR47, 0xFF, 0x6F} +}; + +#define NUM_TOTAL_K400_LCD_RES_8X6_16X12 ARRAY_SIZE(K400_LCD_RES_8X6_16X12) + +struct io_reg K400_LCD_RES_10X7_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xAF}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x45}, {VIASR, SR47, 0xFF, 0x4A} +}; + +#define NUM_TOTAL_K400_LCD_RES_10X7_16X12 ARRAY_SIZE(K400_LCD_RES_10X7_16X12) + +struct io_reg K400_LCD_RES_12X10_16X12[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00}, + {VIACR, CR5D, 0x40, 0x40}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xD4}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x47}, {VIASR, SR47, 0xFF, 0x7C} +}; + +#define NUM_TOTAL_K400_LCD_RES_12X10_16X12 ARRAY_SIZE(K400_LCD_RES_12X10_16X12) + +/* Panel 1400x1050 */ +struct io_reg K400_LCD_RES_6X4_14X10[] = { + /* 640x400 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, + {VIACR, CR5D, 0x40, 0x24}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x63}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19} +}; + +#define NUM_TOTAL_K400_LCD_RES_6X4_14X10 ARRAY_SIZE(K400_LCD_RES_6X4_14X10) + +struct io_reg K400_LCD_RES_8X6_14X10[] = { + /* 800x600 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, + {VIACR, CR5D, 0x40, 0x24}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x83}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21} +}; + +#define NUM_TOTAL_K400_LCD_RES_8X6_14X10 ARRAY_SIZE(K400_LCD_RES_8X6_14X10) + +struct io_reg K400_LCD_RES_10X7_14X10[] = { + /* 1024x768 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, + {VIACR, CR5D, 0x40, 0x24}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xA7}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E} +}; + +#define NUM_TOTAL_K400_LCD_RES_10X7_14X10 ARRAY_SIZE(K400_LCD_RES_10X7_14X10) + +struct io_reg K400_LCD_RES_12X10_14X10[] = { + /* 1280x768, 1280x960, 1280x1024 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75}, + {VIACR, CR5D, 0x40, 0x24}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xD2}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79} +}; + +#define NUM_TOTAL_K400_LCD_RES_12X10_14X10 ARRAY_SIZE(K400_LCD_RES_12X10_14X10) + +/* ++++++ K400 ++++++ */ +/* Panel 1366x768 */ +struct io_reg K400_LCD_RES_6X4_1366X7[] = { + /* 640x400 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B}, + {VIACR, CR5D, 0x40, 0x13}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x64}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C} +}; + +#define NUM_TOTAL_K400_LCD_RES_6X4_1366X7 ARRAY_SIZE(K400_LCD_RES_6X4_1366X7) + +struct io_reg K400_LCD_RES_7X4_1366X7[] = { + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B}, + {VIACR, CR5D, 0x40, 0x13}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x75}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10} +}; + +#define NUM_TOTAL_K400_LCD_RES_7X4_1366X7 ARRAY_SIZE(K400_LCD_RES_7X4_1366X7) + +struct io_reg K400_LCD_RES_8X6_1366X7[] = { + /* 800x600 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B}, + {VIACR, CR5D, 0x40, 0x13}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x82}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9} +}; + +#define NUM_TOTAL_K400_LCD_RES_8X6_1366X7 ARRAY_SIZE(K400_LCD_RES_8X6_1366X7) + +struct io_reg K400_LCD_RES_10X7_1366X7[] = { + /* 1024x768 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, + {VIACR, CR5D, 0x40, 0x24}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xA7}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E} +}; + +#define NUM_TOTAL_K400_LCD_RES_10X7_1366X7 ARRAY_SIZE(K400_LCD_RES_10X7_1366X7) + +struct io_reg K400_LCD_RES_12X10_1366X7[] = { + /* 1280x768, 1280x960, 1280x1024 */ + /* IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56}, + /* IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75}, + {VIACR, CR5D, 0x40, 0x24}, + /* IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44}, + /* IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xD2}, + /* IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04}, + /* VCLK */ + {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79} +}; + +#define NUM_TOTAL_K400_LCD_RES_12X10_1366X7\ + ARRAY_SIZE(K400_LCD_RES_12X10_1366X7) + +/* ++++++ K400 ++++++ */ +/* Panel 1280x1024 */ +struct io_reg K400_LCD_RES_6X4_12X10[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74}, + {VIACR, CR5D, 0x40, 0x1C}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x34}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x63}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xAA}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19} +}; + +#define NUM_TOTAL_K400_LCD_RES_6X4_12X10 ARRAY_SIZE(K400_LCD_RES_6X4_12X10) + +struct io_reg K400_LCD_RES_7X4_12X10[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74}, + {VIACR, CR5D, 0x40, 0x1C}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x68}, {VIACR, CR71, 0x08, 0x34}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x6C}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xA8}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0xED} +}; + +#define NUM_TOTAL_K400_LCD_RES_7X4_12X10 ARRAY_SIZE(K400_LCD_RES_7X4_12X10) + +struct io_reg K400_LCD_RES_8X6_12X10[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74}, + {VIACR, CR5D, 0x40, 0x1C}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x34}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x83}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21} +}; + +#define NUM_TOTAL_K400_LCD_RES_8X6_12X10 ARRAY_SIZE(K400_LCD_RES_8X6_12X10) + +struct io_reg K400_LCD_RES_10X7_12X10[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74}, + {VIACR, CR5D, 0x40, 0x1C}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x34}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0xA7}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x04}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E} +}; + +#define NUM_TOTAL_K400_LCD_RES_10X7_12X10 ARRAY_SIZE(K400_LCD_RES_10X7_12X10) + +/* ++++++ K400 ++++++ */ +/* Panel 1024x768 */ +struct io_reg K400_LCD_RES_6X4_10X7[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B}, + {VIACR, CR5D, 0x40, 0x13}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x64}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C} +}; + +#define NUM_TOTAL_K400_LCD_RES_6X4_10X7 ARRAY_SIZE(K400_LCD_RES_6X4_10X7) + +struct io_reg K400_LCD_RES_7X4_10X7[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B}, + {VIACR, CR5D, 0x40, 0x13}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x75}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10} +}; + +#define NUM_TOTAL_K400_LCD_RES_7X4_10X7 ARRAY_SIZE(K400_LCD_RES_7X4_10X7) + +struct io_reg K400_LCD_RES_8X6_10X7[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B}, + {VIACR, CR5D, 0x40, 0x13}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x82}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9} +}; + +#define NUM_TOTAL_K400_LCD_RES_8X6_10X7 ARRAY_SIZE(K400_LCD_RES_8X6_10X7) + +/* ++++++ K400 ++++++ */ +/* Panel 800x600 */ +struct io_reg K400_LCD_RES_6X4_8X6[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x1A}, {VIACR, CR55, 0x0F, 0x34}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x1A}, {VIACR, CR54, 0x38, 0xE3}, + {VIACR, CR5D, 0x40, 0x12}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x22}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x63}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0x6E}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0x86}, {VIASR, SR47, 0xFF, 0xB3} +}; + +#define NUM_TOTAL_K400_LCD_RES_6X4_8X6 ARRAY_SIZE(K400_LCD_RES_6X4_8X6) + +struct io_reg K400_LCD_RES_7X4_8X6[] = { + /*IGA2 Horizontal Total */ + {VIACR, CR50, 0xFF, 0x1F}, {VIACR, CR55, 0x0F, 0x34}, + /*IGA2 Horizontal Blank End */ + {VIACR, CR53, 0xFF, 0x1F}, {VIACR, CR54, 0x38, 0xE3}, + {VIACR, CR5D, 0x40, 0x12}, + /*IGA2 Horizontal Total Shadow */ + {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x22}, + /*IGA2 Horizontal Blank End Shadow */ + {VIACR, CR6E, 0xFF, 0x83}, + /*IGA2 Offset */ + {VIACR, CR66, 0xFF, 0x78}, {VIACR, CR67, 0x03, 0x00}, + /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x59} +}; + +#define NUM_TOTAL_K400_LCD_RES_7X4_8X6 ARRAY_SIZE(K400_LCD_RES_7X4_8X6) + +#endif /* __LCDTBL_H__ */ diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h new file mode 100644 index 00000000000..2e1254da9c8 --- /dev/null +++ b/drivers/video/via/share.h @@ -0,0 +1,1105 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SHARE_H__ +#define __SHARE_H__ + +/* Define Return Value */ +#define FAIL -1 +#define OK 1 + +#ifndef NULL +#define NULL 0 +#endif + +/* Define Bit Field */ +#define BIT0 0x01 +#define BIT1 0x02 +#define BIT2 0x04 +#define BIT3 0x08 +#define BIT4 0x10 +#define BIT5 0x20 +#define BIT6 0x40 +#define BIT7 0x80 + +/* Video Memory Size */ +#define VIDEO_MEMORY_SIZE_16M 0x1000000 + +/* Definition Mode Index +*/ +#define VIA_RES_640X480 0 +#define VIA_RES_800X600 1 +#define VIA_RES_1024X768 2 +#define VIA_RES_1152X864 3 +#define VIA_RES_1280X1024 4 +#define VIA_RES_1600X1200 5 +#define VIA_RES_1440X1050 6 +#define VIA_RES_1280X768 7 +#define VIA_RES_1280X960 8 +#define VIA_RES_1920X1440 9 +#define VIA_RES_848X480 10 +#define VIA_RES_1400X1050 11 +#define VIA_RES_720X480 12 +#define VIA_RES_720X576 13 +#define VIA_RES_1024X512 14 +#define VIA_RES_856X480 15 +#define VIA_RES_1024X576 16 +#define VIA_RES_640X400 17 +#define VIA_RES_1280X720 18 +#define VIA_RES_1920X1080 19 +#define VIA_RES_800X480 20 +#define VIA_RES_1368X768 21 +#define VIA_RES_1024X600 22 +#define VIA_RES_1280X800 23 +#define VIA_RES_1680X1050 24 +#define VIA_RES_960X600 25 +#define VIA_RES_1000X600 26 +#define VIA_RES_1088X612 27 +#define VIA_RES_1152X720 28 +#define VIA_RES_1200X720 29 +#define VIA_RES_1280X600 30 +#define VIA_RES_1360X768 31 +#define VIA_RES_1366X768 32 +#define VIA_RES_1440X900 33 +#define VIA_RES_1600X900 34 +#define VIA_RES_1600X1024 35 +#define VIA_RES_1792X1344 36 +#define VIA_RES_1856X1392 37 +#define VIA_RES_1920X1200 38 +#define VIA_RES_2048X1536 39 +#define VIA_RES_480X640 40 + +/*Reduce Blanking*/ +#define VIA_RES_1360X768_RB 131 +#define VIA_RES_1440X900_RB 133 +#define VIA_RES_1400X1050_RB 111 +#define VIA_RES_1600X900_RB 134 +#define VIA_RES_1680X1050_RB 124 +#define VIA_RES_1920X1080_RB 119 +#define VIA_RES_1920X1200_RB 138 + +#define VIA_RES_INVALID 255 + +/* standard VGA IO port +*/ +#define VIARMisc 0x3CC +#define VIAWMisc 0x3C2 +#define VIAStatus 0x3DA +#define VIACR 0x3D4 +#define VIASR 0x3C4 +#define VIAGR 0x3CE +#define VIAAR 0x3C0 + +#define StdCR 0x19 +#define StdSR 0x04 +#define StdGR 0x09 +#define StdAR 0x14 + +#define PatchCR 11 + +/* Display path */ +#define IGA1 1 +#define IGA2 2 +#define IGA1_IGA2 3 + +/* Define Color Depth */ +#define MODE_8BPP 1 +#define MODE_16BPP 2 +#define MODE_32BPP 4 + +#define GR20 0x20 +#define GR21 0x21 +#define GR22 0x22 + +/* Sequencer Registers */ +#define SR01 0x01 +#define SR10 0x10 +#define SR12 0x12 +#define SR15 0x15 +#define SR16 0x16 +#define SR17 0x17 +#define SR18 0x18 +#define SR1B 0x1B +#define SR1A 0x1A +#define SR1C 0x1C +#define SR1D 0x1D +#define SR1E 0x1E +#define SR1F 0x1F +#define SR20 0x20 +#define SR21 0x21 +#define SR22 0x22 +#define SR2A 0x2A +#define SR2D 0x2D +#define SR2E 0x2E + +#define SR30 0x30 +#define SR39 0x39 +#define SR3D 0x3D +#define SR3E 0x3E +#define SR3F 0x3F +#define SR40 0x40 +#define SR43 0x43 +#define SR44 0x44 +#define SR45 0x45 +#define SR46 0x46 +#define SR47 0x47 +#define SR48 0x48 +#define SR49 0x49 +#define SR4A 0x4A +#define SR4B 0x4B +#define SR4C 0x4C +#define SR52 0x52 +#define SR5E 0x5E +#define SR65 0x65 + +/* CRT Controller Registers */ +#define CR00 0x00 +#define CR01 0x01 +#define CR02 0x02 +#define CR03 0x03 +#define CR04 0x04 +#define CR05 0x05 +#define CR06 0x06 +#define CR07 0x07 +#define CR08 0x08 +#define CR09 0x09 +#define CR0A 0x0A +#define CR0B 0x0B +#define CR0C 0x0C +#define CR0D 0x0D +#define CR0E 0x0E +#define CR0F 0x0F +#define CR10 0x10 +#define CR11 0x11 +#define CR12 0x12 +#define CR13 0x13 +#define CR14 0x14 +#define CR15 0x15 +#define CR16 0x16 +#define CR17 0x17 +#define CR18 0x18 + +/* Extend CRT Controller Registers */ +#define CR30 0x30 +#define CR31 0x31 +#define CR32 0x32 +#define CR33 0x33 +#define CR34 0x34 +#define CR35 0x35 +#define CR36 0x36 +#define CR37 0x37 +#define CR38 0x38 +#define CR39 0x39 +#define CR3A 0x3A +#define CR3B 0x3B +#define CR3C 0x3C +#define CR3D 0x3D +#define CR3E 0x3E +#define CR3F 0x3F +#define CR40 0x40 +#define CR41 0x41 +#define CR42 0x42 +#define CR43 0x43 +#define CR44 0x44 +#define CR45 0x45 +#define CR46 0x46 +#define CR47 0x47 +#define CR48 0x48 +#define CR49 0x49 +#define CR4A 0x4A +#define CR4B 0x4B +#define CR4C 0x4C +#define CR4D 0x4D +#define CR4E 0x4E +#define CR4F 0x4F +#define CR50 0x50 +#define CR51 0x51 +#define CR52 0x52 +#define CR53 0x53 +#define CR54 0x54 +#define CR55 0x55 +#define CR56 0x56 +#define CR57 0x57 +#define CR58 0x58 +#define CR59 0x59 +#define CR5A 0x5A +#define CR5B 0x5B +#define CR5C 0x5C +#define CR5D 0x5D +#define CR5E 0x5E +#define CR5F 0x5F +#define CR60 0x60 +#define CR61 0x61 +#define CR62 0x62 +#define CR63 0x63 +#define CR64 0x64 +#define CR65 0x65 +#define CR66 0x66 +#define CR67 0x67 +#define CR68 0x68 +#define CR69 0x69 +#define CR6A 0x6A +#define CR6B 0x6B +#define CR6C 0x6C +#define CR6D 0x6D +#define CR6E 0x6E +#define CR6F 0x6F +#define CR70 0x70 +#define CR71 0x71 +#define CR72 0x72 +#define CR73 0x73 +#define CR74 0x74 +#define CR75 0x75 +#define CR76 0x76 +#define CR77 0x77 +#define CR78 0x78 +#define CR79 0x79 +#define CR7A 0x7A +#define CR7B 0x7B +#define CR7C 0x7C +#define CR7D 0x7D +#define CR7E 0x7E +#define CR7F 0x7F +#define CR80 0x80 +#define CR81 0x81 +#define CR82 0x82 +#define CR83 0x83 +#define CR84 0x84 +#define CR85 0x85 +#define CR86 0x86 +#define CR87 0x87 +#define CR88 0x88 +#define CR89 0x89 +#define CR8A 0x8A +#define CR8B 0x8B +#define CR8C 0x8C +#define CR8D 0x8D +#define CR8E 0x8E +#define CR8F 0x8F +#define CR90 0x90 +#define CR91 0x91 +#define CR92 0x92 +#define CR93 0x93 +#define CR94 0x94 +#define CR95 0x95 +#define CR96 0x96 +#define CR97 0x97 +#define CR98 0x98 +#define CR99 0x99 +#define CR9A 0x9A +#define CR9B 0x9B +#define CR9C 0x9C +#define CR9D 0x9D +#define CR9E 0x9E +#define CR9F 0x9F +#define CRA0 0xA0 +#define CRA1 0xA1 +#define CRA2 0xA2 +#define CRA3 0xA3 +#define CRD2 0xD2 +#define CRD3 0xD3 +#define CRD4 0xD4 + +/* LUT Table*/ +#define LUT_DATA 0x3C9 /* DACDATA */ +#define LUT_INDEX_READ 0x3C7 /* DACRX */ +#define LUT_INDEX_WRITE 0x3C8 /* DACWX */ +#define DACMASK 0x3C6 + +/* Definition Device */ +#define DEVICE_CRT 0x01 +#define DEVICE_DVI 0x03 +#define DEVICE_LCD 0x04 + +/* Device output interface */ +#define INTERFACE_NONE 0x00 +#define INTERFACE_ANALOG_RGB 0x01 +#define INTERFACE_DVP0 0x02 +#define INTERFACE_DVP1 0x03 +#define INTERFACE_DFP_HIGH 0x04 +#define INTERFACE_DFP_LOW 0x05 +#define INTERFACE_DFP 0x06 +#define INTERFACE_LVDS0 0x07 +#define INTERFACE_LVDS1 0x08 +#define INTERFACE_LVDS0LVDS1 0x09 +#define INTERFACE_TMDS 0x0A + +#define HW_LAYOUT_LCD_ONLY 0x01 +#define HW_LAYOUT_DVI_ONLY 0x02 +#define HW_LAYOUT_LCD_DVI 0x03 +#define HW_LAYOUT_LCD1_LCD2 0x04 +#define HW_LAYOUT_LCD_EXTERNAL_LCD2 0x10 + +/* Definition Refresh Rate */ +#define REFRESH_50 50 +#define REFRESH_60 60 +#define REFRESH_75 75 +#define REFRESH_85 85 +#define REFRESH_100 100 +#define REFRESH_120 120 + +/* Definition Sync Polarity*/ +#define NEGATIVE 1 +#define POSITIVE 0 + +/*480x640@60 Sync Polarity (GTF) +*/ +#define M480X640_R60_HSP NEGATIVE +#define M480X640_R60_VSP POSITIVE + +/*640x480@60 Sync Polarity (VESA Mode) +*/ +#define M640X480_R60_HSP NEGATIVE +#define M640X480_R60_VSP NEGATIVE + +/*640x480@75 Sync Polarity (VESA Mode) +*/ +#define M640X480_R75_HSP NEGATIVE +#define M640X480_R75_VSP NEGATIVE + +/*640x480@85 Sync Polarity (VESA Mode) +*/ +#define M640X480_R85_HSP NEGATIVE +#define M640X480_R85_VSP NEGATIVE + +/*640x480@100 Sync Polarity (GTF Mode) +*/ +#define M640X480_R100_HSP NEGATIVE +#define M640X480_R100_VSP POSITIVE + +/*640x480@120 Sync Polarity (GTF Mode) +*/ +#define M640X480_R120_HSP NEGATIVE +#define M640X480_R120_VSP POSITIVE + +/*720x480@60 Sync Polarity (GTF Mode) +*/ +#define M720X480_R60_HSP NEGATIVE +#define M720X480_R60_VSP POSITIVE + +/*720x576@60 Sync Polarity (GTF Mode) +*/ +#define M720X576_R60_HSP NEGATIVE +#define M720X576_R60_VSP POSITIVE + +/*800x600@60 Sync Polarity (VESA Mode) +*/ +#define M800X600_R60_HSP POSITIVE +#define M800X600_R60_VSP POSITIVE + +/*800x600@75 Sync Polarity (VESA Mode) +*/ +#define M800X600_R75_HSP POSITIVE +#define M800X600_R75_VSP POSITIVE + +/*800x600@85 Sync Polarity (VESA Mode) +*/ +#define M800X600_R85_HSP POSITIVE +#define M800X600_R85_VSP POSITIVE + +/*800x600@100 Sync Polarity (GTF Mode) +*/ +#define M800X600_R100_HSP NEGATIVE +#define M800X600_R100_VSP POSITIVE + +/*800x600@120 Sync Polarity (GTF Mode) +*/ +#define M800X600_R120_HSP NEGATIVE +#define M800X600_R120_VSP POSITIVE + +/*800x480@60 Sync Polarity (CVT Mode) +*/ +#define M800X480_R60_HSP NEGATIVE +#define M800X480_R60_VSP POSITIVE + +/*848x480@60 Sync Polarity (CVT Mode) +*/ +#define M848X480_R60_HSP NEGATIVE +#define M848X480_R60_VSP POSITIVE + +/*852x480@60 Sync Polarity (GTF Mode) +*/ +#define M852X480_R60_HSP NEGATIVE +#define M852X480_R60_VSP POSITIVE + +/*1024x512@60 Sync Polarity (GTF Mode) +*/ +#define M1024X512_R60_HSP NEGATIVE +#define M1024X512_R60_VSP POSITIVE + +/*1024x600@60 Sync Polarity (GTF Mode) +*/ +#define M1024X600_R60_HSP NEGATIVE +#define M1024X600_R60_VSP POSITIVE + +/*1024x768@60 Sync Polarity (VESA Mode) +*/ +#define M1024X768_R60_HSP NEGATIVE +#define M1024X768_R60_VSP NEGATIVE + +/*1024x768@75 Sync Polarity (VESA Mode) +*/ +#define M1024X768_R75_HSP POSITIVE +#define M1024X768_R75_VSP POSITIVE + +/*1024x768@85 Sync Polarity (VESA Mode) +*/ +#define M1024X768_R85_HSP POSITIVE +#define M1024X768_R85_VSP POSITIVE + +/*1024x768@100 Sync Polarity (GTF Mode) +*/ +#define M1024X768_R100_HSP NEGATIVE +#define M1024X768_R100_VSP POSITIVE + +/*1152x864@75 Sync Polarity (VESA Mode) +*/ +#define M1152X864_R75_HSP POSITIVE +#define M1152X864_R75_VSP POSITIVE + +/*1280x720@60 Sync Polarity (GTF Mode) +*/ +#define M1280X720_R60_HSP NEGATIVE +#define M1280X720_R60_VSP POSITIVE + +/* 1280x768@50 Sync Polarity (GTF Mode) */ +#define M1280X768_R50_HSP NEGATIVE +#define M1280X768_R50_VSP POSITIVE + +/*1280x768@60 Sync Polarity (GTF Mode) +*/ +#define M1280X768_R60_HSP NEGATIVE +#define M1280X768_R60_VSP POSITIVE + +/*1280x800@60 Sync Polarity (CVT Mode) +*/ +#define M1280X800_R60_HSP NEGATIVE +#define M1280X800_R60_VSP POSITIVE + +/*1280x960@60 Sync Polarity (VESA Mode) +*/ +#define M1280X960_R60_HSP POSITIVE +#define M1280X960_R60_VSP POSITIVE + +/*1280x1024@60 Sync Polarity (VESA Mode) +*/ +#define M1280X1024_R60_HSP POSITIVE +#define M1280X1024_R60_VSP POSITIVE + +/* 1360x768@60 Sync Polarity (CVT Mode) */ +#define M1360X768_R60_HSP POSITIVE +#define M1360X768_R60_VSP POSITIVE + +/* 1360x768@60 Sync Polarity (CVT Reduce Blanking Mode) */ +#define M1360X768_RB_R60_HSP POSITIVE +#define M1360X768_RB_R60_VSP NEGATIVE + +/* 1368x768@50 Sync Polarity (GTF Mode) */ +#define M1368X768_R50_HSP NEGATIVE +#define M1368X768_R50_VSP POSITIVE + +/* 1368x768@60 Sync Polarity (VESA Mode) */ +#define M1368X768_R60_HSP NEGATIVE +#define M1368X768_R60_VSP POSITIVE + +/*1280x1024@75 Sync Polarity (VESA Mode) +*/ +#define M1280X1024_R75_HSP POSITIVE +#define M1280X1024_R75_VSP POSITIVE + +/*1280x1024@85 Sync Polarity (VESA Mode) +*/ +#define M1280X1024_R85_HSP POSITIVE +#define M1280X1024_R85_VSP POSITIVE + +/*1440x1050@60 Sync Polarity (GTF Mode) +*/ +#define M1440X1050_R60_HSP NEGATIVE +#define M1440X1050_R60_VSP POSITIVE + +/*1600x1200@60 Sync Polarity (VESA Mode) +*/ +#define M1600X1200_R60_HSP POSITIVE +#define M1600X1200_R60_VSP POSITIVE + +/*1600x1200@75 Sync Polarity (VESA Mode) +*/ +#define M1600X1200_R75_HSP POSITIVE +#define M1600X1200_R75_VSP POSITIVE + +/* 1680x1050@60 Sync Polarity (CVT Mode) */ +#define M1680x1050_R60_HSP NEGATIVE +#define M1680x1050_R60_VSP NEGATIVE + +/* 1680x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */ +#define M1680x1050_RB_R60_HSP POSITIVE +#define M1680x1050_RB_R60_VSP NEGATIVE + +/* 1680x1050@75 Sync Polarity (CVT Mode) */ +#define M1680x1050_R75_HSP NEGATIVE +#define M1680x1050_R75_VSP POSITIVE + +/*1920x1080@60 Sync Polarity (CVT Mode) +*/ +#define M1920X1080_R60_HSP NEGATIVE +#define M1920X1080_R60_VSP POSITIVE + +/* 1920x1080@60 Sync Polarity (CVT Reduce Blanking Mode) */ +#define M1920X1080_RB_R60_HSP POSITIVE +#define M1920X1080_RB_R60_VSP NEGATIVE + +/*1920x1440@60 Sync Polarity (VESA Mode) +*/ +#define M1920X1440_R60_HSP NEGATIVE +#define M1920X1440_R60_VSP POSITIVE + +/*1920x1440@75 Sync Polarity (VESA Mode) +*/ +#define M1920X1440_R75_HSP NEGATIVE +#define M1920X1440_R75_VSP POSITIVE + +#if 0 +/* 1400x1050@60 Sync Polarity (VESA Mode) */ +#define M1400X1050_R60_HSP NEGATIVE +#define M1400X1050_R60_VSP NEGATIVE +#endif + +/* 1400x1050@60 Sync Polarity (CVT Mode) */ +#define M1400X1050_R60_HSP NEGATIVE +#define M1400X1050_R60_VSP POSITIVE + +/* 1400x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */ +#define M1400X1050_RB_R60_HSP POSITIVE +#define M1400X1050_RB_R60_VSP NEGATIVE + +/* 1400x1050@75 Sync Polarity (CVT Mode) */ +#define M1400X1050_R75_HSP NEGATIVE +#define M1400X1050_R75_VSP POSITIVE + +/* 960x600@60 Sync Polarity (CVT Mode) */ +#define M960X600_R60_HSP NEGATIVE +#define M960X600_R60_VSP POSITIVE + +/* 1000x600@60 Sync Polarity (GTF Mode) */ +#define M1000X600_R60_HSP NEGATIVE +#define M1000X600_R60_VSP POSITIVE + +/* 1024x576@60 Sync Polarity (GTF Mode) */ +#define M1024X576_R60_HSP NEGATIVE +#define M1024X576_R60_VSP POSITIVE + +/*1024x600@60 Sync Polarity (GTF Mode)*/ +#define M1024X600_R60_HSP NEGATIVE +#define M1024X600_R60_VSP POSITIVE + +/* 1088x612@60 Sync Polarity (CVT Mode) */ +#define M1088X612_R60_HSP NEGATIVE +#define M1088X612_R60_VSP POSITIVE + +/* 1152x720@60 Sync Polarity (CVT Mode) */ +#define M1152X720_R60_HSP NEGATIVE +#define M1152X720_R60_VSP POSITIVE + +/* 1200x720@60 Sync Polarity (GTF Mode) */ +#define M1200X720_R60_HSP NEGATIVE +#define M1200X720_R60_VSP POSITIVE + +/* 1280x600@60 Sync Polarity (GTF Mode) */ +#define M1280x600_R60_HSP NEGATIVE +#define M1280x600_R60_VSP POSITIVE + +/* 1280x720@50 Sync Polarity (GTF Mode) */ +#define M1280X720_R50_HSP NEGATIVE +#define M1280X720_R50_VSP POSITIVE + +/* 1280x720@60 Sync Polarity (CEA Mode) */ +#define M1280X720_CEA_R60_HSP POSITIVE +#define M1280X720_CEA_R60_VSP POSITIVE + +/* 1440x900@60 Sync Polarity (CVT Mode) */ +#define M1440X900_R60_HSP NEGATIVE +#define M1440X900_R60_VSP POSITIVE + +/* 1440x900@75 Sync Polarity (CVT Mode) */ +#define M1440X900_R75_HSP NEGATIVE +#define M1440X900_R75_VSP POSITIVE + +/* 1440x900@60 Sync Polarity (CVT Reduce Blanking Mode) */ +#define M1440X900_RB_R60_HSP POSITIVE +#define M1440X900_RB_R60_VSP NEGATIVE + +/* 1600x900@60 Sync Polarity (CVT Mode) */ +#define M1600X900_R60_HSP NEGATIVE +#define M1600X900_R60_VSP POSITIVE + +/* 1600x900@60 Sync Polarity (CVT Reduce Blanking Mode) */ +#define M1600X900_RB_R60_HSP POSITIVE +#define M1600X900_RB_R60_VSP NEGATIVE + +/* 1600x1024@60 Sync Polarity (GTF Mode) */ +#define M1600X1024_R60_HSP NEGATIVE +#define M1600X1024_R60_VSP POSITIVE + +/* 1792x1344@60 Sync Polarity (DMT Mode) */ +#define M1792x1344_R60_HSP NEGATIVE +#define M1792x1344_R60_VSP POSITIVE + +/* 1856x1392@60 Sync Polarity (DMT Mode) */ +#define M1856x1392_R60_HSP NEGATIVE +#define M1856x1392_R60_VSP POSITIVE + +/* 1920x1200@60 Sync Polarity (CVT Mode) */ +#define M1920X1200_R60_HSP NEGATIVE +#define M1920X1200_R60_VSP POSITIVE + +/* 1920x1200@60 Sync Polarity (CVT Reduce Blanking Mode) */ +#define M1920X1200_RB_R60_HSP POSITIVE +#define M1920X1200_RB_R60_VSP NEGATIVE + +/* 1920x1080@60 Sync Polarity (CEA Mode) */ +#define M1920X1080_CEA_R60_HSP POSITIVE +#define M1920X1080_CEA_R60_VSP POSITIVE + +/* 2048x1536@60 Sync Polarity (CVT Mode) */ +#define M2048x1536_R60_HSP NEGATIVE +#define M2048x1536_R60_VSP POSITIVE + +/* define PLL index: */ +#define CLK_25_175M 25175000 +#define CLK_26_880M 26880000 +#define CLK_29_581M 29581000 +#define CLK_31_490M 31490000 +#define CLK_31_500M 31500000 +#define CLK_31_728M 31728000 +#define CLK_32_668M 32688000 +#define CLK_36_000M 36000000 +#define CLK_40_000M 40000000 +#define CLK_41_291M 41291000 +#define CLK_43_163M 43163000 +#define CLK_45_250M 45250000 /* 45.46MHz */ +#define CLK_46_000M 46000000 +#define CLK_46_996M 46996000 +#define CLK_48_000M 48000000 +#define CLK_48_875M 48875000 +#define CLK_49_500M 49500000 +#define CLK_52_406M 52406000 +#define CLK_52_977M 52977000 +#define CLK_56_250M 56250000 +#define CLK_60_466M 60466000 +#define CLK_61_500M 61500000 +#define CLK_65_000M 65000000 +#define CLK_65_178M 65178000 +#define CLK_66_750M 66750000 /* 67.116MHz */ +#define CLK_68_179M 68179000 +#define CLK_69_924M 69924000 +#define CLK_70_159M 70159000 +#define CLK_72_000M 72000000 +#define CLK_74_270M 74270000 +#define CLK_78_750M 78750000 +#define CLK_80_136M 80136000 +#define CLK_83_375M 83375000 +#define CLK_83_950M 83950000 +#define CLK_84_750M 84750000 /* 84.537Mhz */ +#define CLK_85_860M 85860000 +#define CLK_88_750M 88750000 +#define CLK_94_500M 94500000 +#define CLK_97_750M 97750000 +#define CLK_101_000M 101000000 +#define CLK_106_500M 106500000 +#define CLK_108_000M 108000000 +#define CLK_113_309M 113309000 +#define CLK_118_840M 118840000 +#define CLK_119_000M 119000000 +#define CLK_121_750M 121750000 /* 121.704MHz */ +#define CLK_125_104M 125104000 +#define CLK_133_308M 133308000 +#define CLK_135_000M 135000000 +#define CLK_136_700M 136700000 +#define CLK_138_400M 138400000 +#define CLK_146_760M 146760000 +#define CLK_148_500M 148500000 + +#define CLK_153_920M 153920000 +#define CLK_156_000M 156000000 +#define CLK_157_500M 157500000 +#define CLK_162_000M 162000000 +#define CLK_187_000M 187000000 +#define CLK_193_295M 193295000 +#define CLK_202_500M 202500000 +#define CLK_204_000M 204000000 +#define CLK_218_500M 218500000 +#define CLK_234_000M 234000000 +#define CLK_267_250M 267250000 +#define CLK_297_500M 297500000 +#define CLK_74_481M 74481000 +#define CLK_172_798M 172798000 +#define CLK_122_614M 122614000 + +/* CLE266 PLL value +*/ +#define CLE266_PLL_25_175M 0x0000C763 +#define CLE266_PLL_26_880M 0x0000440F +#define CLE266_PLL_29_581M 0x00008421 +#define CLE266_PLL_31_490M 0x00004721 +#define CLE266_PLL_31_500M 0x0000C3B5 +#define CLE266_PLL_31_728M 0x0000471F +#define CLE266_PLL_32_668M 0x0000C449 +#define CLE266_PLL_36_000M 0x0000C5E5 +#define CLE266_PLL_40_000M 0x0000C459 +#define CLE266_PLL_41_291M 0x00004417 +#define CLE266_PLL_43_163M 0x0000C579 +#define CLE266_PLL_45_250M 0x0000C57F /* 45.46MHz */ +#define CLE266_PLL_46_000M 0x0000875A +#define CLE266_PLL_46_996M 0x0000C4E9 +#define CLE266_PLL_48_000M 0x00001443 +#define CLE266_PLL_48_875M 0x00001D63 +#define CLE266_PLL_49_500M 0x00008653 +#define CLE266_PLL_52_406M 0x0000C475 +#define CLE266_PLL_52_977M 0x00004525 +#define CLE266_PLL_56_250M 0x000047B7 +#define CLE266_PLL_60_466M 0x0000494C +#define CLE266_PLL_61_500M 0x00001456 +#define CLE266_PLL_65_000M 0x000086ED +#define CLE266_PLL_65_178M 0x0000855B +#define CLE266_PLL_66_750M 0x0000844B /* 67.116MHz */ +#define CLE266_PLL_68_179M 0x00000413 +#define CLE266_PLL_69_924M 0x00001153 +#define CLE266_PLL_70_159M 0x00001462 +#define CLE266_PLL_72_000M 0x00001879 +#define CLE266_PLL_74_270M 0x00004853 +#define CLE266_PLL_78_750M 0x00004321 +#define CLE266_PLL_80_136M 0x0000051C +#define CLE266_PLL_83_375M 0x0000C25D +#define CLE266_PLL_83_950M 0x00000729 +#define CLE266_PLL_84_750M 0x00008576 /* 84.537MHz */ +#define CLE266_PLL_85_860M 0x00004754 +#define CLE266_PLL_88_750M 0x0000051F +#define CLE266_PLL_94_500M 0x00000521 +#define CLE266_PLL_97_750M 0x00004652 +#define CLE266_PLL_101_000M 0x0000497F +#define CLE266_PLL_106_500M 0x00008477 /* 106.491463 MHz */ +#define CLE266_PLL_108_000M 0x00008479 +#define CLE266_PLL_113_309M 0x00000C5F +#define CLE266_PLL_118_840M 0x00004553 +#define CLE266_PLL_119_000M 0x00000D6C +#define CLE266_PLL_121_750M 0x00004555 /* 121.704MHz */ +#define CLE266_PLL_125_104M 0x000006B5 +#define CLE266_PLL_133_308M 0x0000465F +#define CLE266_PLL_135_000M 0x0000455E +#define CLE266_PLL_136_700M 0x00000C73 +#define CLE266_PLL_138_400M 0x00000957 +#define CLE266_PLL_146_760M 0x00004567 +#define CLE266_PLL_148_500M 0x00000853 +#define CLE266_PLL_153_920M 0x00000856 +#define CLE266_PLL_156_000M 0x0000456D +#define CLE266_PLL_157_500M 0x000005B7 +#define CLE266_PLL_162_000M 0x00004571 +#define CLE266_PLL_187_000M 0x00000976 +#define CLE266_PLL_193_295M 0x0000086C +#define CLE266_PLL_202_500M 0x00000763 +#define CLE266_PLL_204_000M 0x00000764 +#define CLE266_PLL_218_500M 0x0000065C +#define CLE266_PLL_234_000M 0x00000662 +#define CLE266_PLL_267_250M 0x00000670 +#define CLE266_PLL_297_500M 0x000005E6 +#define CLE266_PLL_74_481M 0x0000051A +#define CLE266_PLL_172_798M 0x00004579 +#define CLE266_PLL_122_614M 0x0000073C + +/* K800 PLL value +*/ +#define K800_PLL_25_175M 0x00539001 +#define K800_PLL_26_880M 0x001C8C80 +#define K800_PLL_29_581M 0x00409080 +#define K800_PLL_31_490M 0x006F9001 +#define K800_PLL_31_500M 0x008B9002 +#define K800_PLL_31_728M 0x00AF9003 +#define K800_PLL_32_668M 0x00909002 +#define K800_PLL_36_000M 0x009F9002 +#define K800_PLL_40_000M 0x00578C02 +#define K800_PLL_41_291M 0x00438C01 +#define K800_PLL_43_163M 0x00778C03 +#define K800_PLL_45_250M 0x007D8C83 /* 45.46MHz */ +#define K800_PLL_46_000M 0x00658C02 +#define K800_PLL_46_996M 0x00818C83 +#define K800_PLL_48_000M 0x00848C83 +#define K800_PLL_48_875M 0x00508C81 +#define K800_PLL_49_500M 0x00518C01 +#define K800_PLL_52_406M 0x00738C02 +#define K800_PLL_52_977M 0x00928C83 +#define K800_PLL_56_250M 0x007C8C02 +#define K800_PLL_60_466M 0x00A78C83 +#define K800_PLL_61_500M 0x00AA8C83 +#define K800_PLL_65_000M 0x006B8C01 +#define K800_PLL_65_178M 0x00B48C83 +#define K800_PLL_66_750M 0x00948C82 /* 67.116MHz */ +#define K800_PLL_68_179M 0x00708C01 +#define K800_PLL_69_924M 0x00C18C83 +#define K800_PLL_70_159M 0x00C28C83 +#define K800_PLL_72_000M 0x009F8C82 +#define K800_PLL_74_270M 0x00ce0c03 +#define K800_PLL_78_750M 0x00408801 +#define K800_PLL_80_136M 0x00428801 +#define K800_PLL_83_375M 0x005B0882 +#define K800_PLL_83_950M 0x00738803 +#define K800_PLL_84_750M 0x00748883 /* 84.477MHz */ +#define K800_PLL_85_860M 0x00768883 +#define K800_PLL_88_750M 0x007A8883 +#define K800_PLL_94_500M 0x00828803 +#define K800_PLL_97_750M 0x00878883 +#define K800_PLL_101_000M 0x008B8883 +#define K800_PLL_106_500M 0x00758882 /* 106.491463 MHz */ +#define K800_PLL_108_000M 0x00778882 +#define K800_PLL_113_309M 0x005D8881 +#define K800_PLL_118_840M 0x00A48883 +#define K800_PLL_119_000M 0x00838882 +#define K800_PLL_121_750M 0x00A88883 /* 121.704MHz */ +#define K800_PLL_125_104M 0x00688801 +#define K800_PLL_133_308M 0x005D8801 +#define K800_PLL_135_000M 0x001A4081 +#define K800_PLL_136_700M 0x00BD8883 +#define K800_PLL_138_400M 0x00728881 +#define K800_PLL_146_760M 0x00CC8883 +#define K800_PLL_148_500M 0x00ce0803 +#define K800_PLL_153_920M 0x00548482 +#define K800_PLL_156_000M 0x006B8483 +#define K800_PLL_157_500M 0x00142080 +#define K800_PLL_162_000M 0x006F8483 +#define K800_PLL_187_000M 0x00818483 +#define K800_PLL_193_295M 0x004F8481 +#define K800_PLL_202_500M 0x00538481 +#define K800_PLL_204_000M 0x008D8483 +#define K800_PLL_218_500M 0x00978483 +#define K800_PLL_234_000M 0x00608401 +#define K800_PLL_267_250M 0x006E8481 +#define K800_PLL_297_500M 0x00A48402 +#define K800_PLL_74_481M 0x007B8C81 +#define K800_PLL_172_798M 0x00778483 +#define K800_PLL_122_614M 0x00878882 + +/* PLL for VT3324 */ +#define CX700_25_175M 0x008B1003 +#define CX700_26_719M 0x00931003 +#define CX700_26_880M 0x00941003 +#define CX700_29_581M 0x00A49003 +#define CX700_31_490M 0x00AE1003 +#define CX700_31_500M 0x00AE1003 +#define CX700_31_728M 0x00AF1003 +#define CX700_32_668M 0x00B51003 +#define CX700_36_000M 0x00C81003 +#define CX700_40_000M 0x006E0C03 +#define CX700_41_291M 0x00710C03 +#define CX700_43_163M 0x00770C03 +#define CX700_45_250M 0x007D0C03 /* 45.46MHz */ +#define CX700_46_000M 0x007F0C03 +#define CX700_46_996M 0x00818C83 +#define CX700_48_000M 0x00840C03 +#define CX700_48_875M 0x00508C81 +#define CX700_49_500M 0x00880C03 +#define CX700_52_406M 0x00730C02 +#define CX700_52_977M 0x00920C03 +#define CX700_56_250M 0x009B0C03 +#define CX700_60_466M 0x00460C00 +#define CX700_61_500M 0x00AA0C03 +#define CX700_65_000M 0x006B0C01 +#define CX700_65_178M 0x006B0C01 +#define CX700_66_750M 0x00940C02 /*67.116MHz */ +#define CX700_68_179M 0x00BC0C03 +#define CX700_69_924M 0x00C10C03 +#define CX700_70_159M 0x00C20C03 +#define CX700_72_000M 0x009F0C02 +#define CX700_74_270M 0x00CE0C03 +#define CX700_74_481M 0x00CE0C03 +#define CX700_78_750M 0x006C0803 +#define CX700_80_136M 0x006E0803 +#define CX700_83_375M 0x005B0882 +#define CX700_83_950M 0x00730803 +#define CX700_84_750M 0x00740803 /* 84.537Mhz */ +#define CX700_85_860M 0x00760803 +#define CX700_88_750M 0x00AC8885 +#define CX700_94_500M 0x00820803 +#define CX700_97_750M 0x00870803 +#define CX700_101_000M 0x008B0803 +#define CX700_106_500M 0x00750802 +#define CX700_108_000M 0x00950803 +#define CX700_113_309M 0x005D0801 +#define CX700_118_840M 0x00A40803 +#define CX700_119_000M 0x00830802 +#define CX700_121_750M 0x00420800 /* 121.704MHz */ +#define CX700_125_104M 0x00AD0803 +#define CX700_133_308M 0x00930802 +#define CX700_135_000M 0x00950802 +#define CX700_136_700M 0x00BD0803 +#define CX700_138_400M 0x00720801 +#define CX700_146_760M 0x00CC0803 +#define CX700_148_500M 0x00a40802 +#define CX700_153_920M 0x00540402 +#define CX700_156_000M 0x006B0403 +#define CX700_157_500M 0x006C0403 +#define CX700_162_000M 0x006F0403 +#define CX700_172_798M 0x00770403 +#define CX700_187_000M 0x00810403 +#define CX700_193_295M 0x00850403 +#define CX700_202_500M 0x008C0403 +#define CX700_204_000M 0x008D0403 +#define CX700_218_500M 0x00970403 +#define CX700_234_000M 0x00600401 +#define CX700_267_250M 0x00B90403 +#define CX700_297_500M 0x00CE0403 +#define CX700_122_614M 0x00870802 + +/* Definition CRTC Timing Index */ +#define H_TOTAL_INDEX 0 +#define H_ADDR_INDEX 1 +#define H_BLANK_START_INDEX 2 +#define H_BLANK_END_INDEX 3 +#define H_SYNC_START_INDEX 4 +#define H_SYNC_END_INDEX 5 +#define V_TOTAL_INDEX 6 +#define V_ADDR_INDEX 7 +#define V_BLANK_START_INDEX 8 +#define V_BLANK_END_INDEX 9 +#define V_SYNC_START_INDEX 10 +#define V_SYNC_END_INDEX 11 +#define H_TOTAL_SHADOW_INDEX 12 +#define H_BLANK_END_SHADOW_INDEX 13 +#define V_TOTAL_SHADOW_INDEX 14 +#define V_ADDR_SHADOW_INDEX 15 +#define V_BLANK_SATRT_SHADOW_INDEX 16 +#define V_BLANK_END_SHADOW_INDEX 17 +#define V_SYNC_SATRT_SHADOW_INDEX 18 +#define V_SYNC_END_SHADOW_INDEX 19 + +/* Definition Video Mode Pixel Clock (picoseconds) +*/ +#define RES_480X640_60HZ_PIXCLOCK 39722 +#define RES_640X480_60HZ_PIXCLOCK 39722 +#define RES_640X480_75HZ_PIXCLOCK 31747 +#define RES_640X480_85HZ_PIXCLOCK 27777 +#define RES_640X480_100HZ_PIXCLOCK 23168 +#define RES_640X480_120HZ_PIXCLOCK 19081 +#define RES_720X480_60HZ_PIXCLOCK 37020 +#define RES_720X576_60HZ_PIXCLOCK 30611 +#define RES_800X600_60HZ_PIXCLOCK 25000 +#define RES_800X600_75HZ_PIXCLOCK 20203 +#define RES_800X600_85HZ_PIXCLOCK 17777 +#define RES_800X600_100HZ_PIXCLOCK 14667 +#define RES_800X600_120HZ_PIXCLOCK 11912 +#define RES_800X480_60HZ_PIXCLOCK 33805 +#define RES_848X480_60HZ_PIXCLOCK 31756 +#define RES_856X480_60HZ_PIXCLOCK 31518 +#define RES_1024X512_60HZ_PIXCLOCK 24218 +#define RES_1024X600_60HZ_PIXCLOCK 20460 +#define RES_1024X768_60HZ_PIXCLOCK 15385 +#define RES_1024X768_75HZ_PIXCLOCK 12699 +#define RES_1024X768_85HZ_PIXCLOCK 10582 +#define RES_1024X768_100HZ_PIXCLOCK 8825 +#define RES_1152X864_75HZ_PIXCLOCK 9259 +#define RES_1280X768_60HZ_PIXCLOCK 12480 +#define RES_1280X800_60HZ_PIXCLOCK 11994 +#define RES_1280X960_60HZ_PIXCLOCK 9259 +#define RES_1280X1024_60HZ_PIXCLOCK 9260 +#define RES_1280X1024_75HZ_PIXCLOCK 7408 +#define RES_1280X768_85HZ_PIXCLOCK 6349 +#define RES_1440X1050_60HZ_PIXCLOCK 7993 +#define RES_1600X1200_60HZ_PIXCLOCK 6172 +#define RES_1600X1200_75HZ_PIXCLOCK 4938 +#define RES_1280X720_60HZ_PIXCLOCK 13426 +#define RES_1920X1080_60HZ_PIXCLOCK 5787 +#define RES_1400X1050_60HZ_PIXCLOCK 8214 +#define RES_1400X1050_75HZ_PIXCLOCK 6410 +#define RES_1368X768_60HZ_PIXCLOCK 11647 +#define RES_960X600_60HZ_PIXCLOCK 22099 +#define RES_1000X600_60HZ_PIXCLOCK 20834 +#define RES_1024X576_60HZ_PIXCLOCK 21278 +#define RES_1088X612_60HZ_PIXCLOCK 18877 +#define RES_1152X720_60HZ_PIXCLOCK 14981 +#define RES_1200X720_60HZ_PIXCLOCK 14253 +#define RES_1280X600_60HZ_PIXCLOCK 16260 +#define RES_1280X720_50HZ_PIXCLOCK 16538 +#define RES_1280X768_50HZ_PIXCLOCK 15342 +#define RES_1366X768_50HZ_PIXCLOCK 14301 +#define RES_1366X768_60HZ_PIXCLOCK 11646 +#define RES_1360X768_60HZ_PIXCLOCK 11799 +#define RES_1440X900_60HZ_PIXCLOCK 9390 +#define RES_1440X900_75HZ_PIXCLOCK 7315 +#define RES_1600X900_60HZ_PIXCLOCK 8415 +#define RES_1600X1024_60HZ_PIXCLOCK 7315 +#define RES_1680X1050_60HZ_PIXCLOCK 6814 +#define RES_1680X1050_75HZ_PIXCLOCK 5348 +#define RES_1792X1344_60HZ_PIXCLOCK 4902 +#define RES_1856X1392_60HZ_PIXCLOCK 4577 +#define RES_1920X1200_60HZ_PIXCLOCK 5173 +#define RES_1920X1440_60HZ_PIXCLOCK 4274 +#define RES_1920X1440_75HZ_PIXCLOCK 3367 +#define RES_2048X1536_60HZ_PIXCLOCK 3742 + +#define RES_1360X768_RB_60HZ_PIXCLOCK 13889 +#define RES_1400X1050_RB_60HZ_PIXCLOCK 9901 +#define RES_1440X900_RB_60HZ_PIXCLOCK 11268 +#define RES_1600X900_RB_60HZ_PIXCLOCK 10230 +#define RES_1680X1050_RB_60HZ_PIXCLOCK 8403 +#define RES_1920X1080_RB_60HZ_PIXCLOCK 7225 +#define RES_1920X1200_RB_60HZ_PIXCLOCK 6497 + +/* LCD display method +*/ +#define LCD_EXPANDSION 0x00 +#define LCD_CENTERING 0x01 + +/* LCD mode +*/ +#define LCD_OPENLDI 0x00 +#define LCD_SPWG 0x01 + +/* Define display timing +*/ +struct display_timing { + u16 hor_total; + u16 hor_addr; + u16 hor_blank_start; + u16 hor_blank_end; + u16 hor_sync_start; + u16 hor_sync_end; + u16 ver_total; + u16 ver_addr; + u16 ver_blank_start; + u16 ver_blank_end; + u16 ver_sync_start; + u16 ver_sync_end; +}; + +struct crt_mode_table { + int refresh_rate; + unsigned long clk; + int h_sync_polarity; + int v_sync_polarity; + struct display_timing crtc; +}; + +struct io_reg { + int port; + u8 index; + u8 mask; + u8 value; +}; + +#endif /* __SHARE_H__ */ diff --git a/drivers/video/via/tbl1636.c b/drivers/video/via/tbl1636.c new file mode 100644 index 00000000000..2d8453429d4 --- /dev/null +++ b/drivers/video/via/tbl1636.c @@ -0,0 +1,71 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" +struct IODATA COMMON_INIT_TBL_VT1636[] = { +/* Index, Mask, Value */ + /* Set panel power sequence timing */ + {0x10, 0xC0, 0x00}, + /* T1: VDD on - Data on. Each increment is 1 ms. (50ms = 031h) */ + {0x0B, 0xFF, 0x40}, + /* T2: Data on - Backlight on. Each increment is 2 ms. (210ms = 068h) */ + {0x0C, 0xFF, 0x31}, + /* T3: Backlight off -Data off. Each increment is 2 ms. (210ms = 068h)*/ + {0x0D, 0xFF, 0x31}, + /* T4: Data off - VDD off. Each increment is 1 ms. (50ms = 031h) */ + {0x0E, 0xFF, 0x68}, + /* T5: VDD off - VDD on. Each increment is 100 ms. (500ms = 04h) */ + {0x0F, 0xFF, 0x68}, + /* LVDS output power up */ + {0x09, 0xA0, 0xA0}, + /* turn on back light */ + {0x10, 0x33, 0x13} +}; + +struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[] = { +/* Index, Mask, Value */ + {0x08, 0xF0, 0xE0} /* Input Data Mode Select */ +}; + +struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[] = { +/* Index, Mask, Value */ + {0x08, 0xF0, 0x00} /* Input Data Mode Select */ +}; + +struct IODATA DITHERING_ENABLE_TBL_VT1636[] = { +/* Index, Mask, Value */ + {0x0A, 0x70, 0x50} +}; + +struct IODATA DITHERING_DISABLE_TBL_VT1636[] = { +/* Index, Mask, Value */ + {0x0A, 0x70, 0x00} +}; + +struct IODATA VDD_ON_TBL_VT1636[] = { +/* Index, Mask, Value */ + {0x10, 0x20, 0x20} +}; + +struct IODATA VDD_OFF_TBL_VT1636[] = { +/* Index, Mask, Value */ + {0x10, 0x20, 0x00} +}; diff --git a/drivers/video/via/tbl1636.h b/drivers/video/via/tbl1636.h new file mode 100644 index 00000000000..d906055f151 --- /dev/null +++ b/drivers/video/via/tbl1636.h @@ -0,0 +1,34 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _TBL1636_H_ +#define _TBL1636_H_ +#include "hw.h" + +extern struct IODATA COMMON_INIT_TBL_VT1636[8]; +extern struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[1]; +extern struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[1]; +extern struct IODATA DITHERING_ENABLE_TBL_VT1636[1]; +extern struct IODATA DITHERING_DISABLE_TBL_VT1636[1]; +extern struct IODATA VDD_ON_TBL_VT1636[1]; +extern struct IODATA VDD_OFF_TBL_VT1636[1]; + +#endif /* _VIA_TBL1636_H_ */ diff --git a/drivers/video/via/tblDPASetting.c b/drivers/video/via/tblDPASetting.c new file mode 100644 index 00000000000..0c4c8cc712f --- /dev/null +++ b/drivers/video/via/tblDPASetting.c @@ -0,0 +1,109 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" +/* For VT3324: */ +struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3324[] = { + /* Panel ID, CLK_SEL_ST1[09], CLK_SEL_ST2[08] */ + {LCD_PANEL_ID0_640X480, 0x00, 0x00}, /* For 640x480 */ + {LCD_PANEL_ID1_800X600, 0x00, 0x00}, /* For 800x600 */ + {LCD_PANEL_ID2_1024X768, 0x00, 0x00}, /* For 1024x768 */ + {LCD_PANEL_ID3_1280X768, 0x00, 0x00}, /* For 1280x768 */ + {LCD_PANEL_ID4_1280X1024, 0x00, 0x00}, /* For 1280x1024 */ + {LCD_PANEL_ID5_1400X1050, 0x00, 0x00}, /* For 1400x1050 */ + {LCD_PANEL_ID6_1600X1200, 0x0B, 0x03} /* For 1600x1200 */ +}; + +struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3324[] = { +/* ClkRange, DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, + DVP1Driving, DFPHigh, DFPLow */ +/* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B, + SR65, CR97, CR99 */ + /* LCK/VCK < 30000000 will use this value */ + {DPA_CLK_RANGE_30M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00}, + /* 30000000 < LCK/VCK < 50000000 will use this value */ + {DPA_CLK_RANGE_30_50M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00}, + /* 50000000 < LCK/VCK < 70000000 will use this value */ + {DPA_CLK_RANGE_50_70M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00}, + /* 70000000 < LCK/VCK < 100000000 will use this value */ + {DPA_CLK_RANGE_70_100M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00}, + /* 100000000 < LCK/VCK < 15000000 will use this value */ + {DPA_CLK_RANGE_100_150M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00}, + /* 15000000 < LCK/VCK will use this value */ + {DPA_CLK_RANGE_150M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0E, 0x00, + 0x00}, +}; + +/* For VT3327: */ +struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3327[] = { + /* Panel ID, CLK_SEL_ST1[09], CLK_SEL_ST2[08] */ + {LCD_PANEL_ID0_640X480, 0x00, 0x00}, /* For 640x480 */ + {LCD_PANEL_ID1_800X600, 0x00, 0x00}, /* For 800x600 */ + {LCD_PANEL_ID2_1024X768, 0x00, 0x00}, /* For 1024x768 */ + {LCD_PANEL_ID3_1280X768, 0x00, 0x00}, /* For 1280x768 */ + {LCD_PANEL_ID4_1280X1024, 0x00, 0x00}, /* For 1280x1024 */ + {LCD_PANEL_ID5_1400X1050, 0x00, 0x00}, /* For 1400x1050 */ + {LCD_PANEL_ID6_1600X1200, 0x00, 0x00} /* For 1600x1200 */ +}; + +struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3327[] = { +/* ClkRange,DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, + DVP1Driving, DFPHigh, DFPLow */ +/* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B, + SR65, CR97, CR99 */ +/* LCK/VCK < 30000000 will use this value */ +{DPA_CLK_RANGE_30M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01}, +/* 30000000 < LCK/VCK < 50000000 will use this value */ +{DPA_CLK_RANGE_30_50M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01}, +/* 50000000 < LCK/VCK < 70000000 will use this value */ +{DPA_CLK_RANGE_50_70M, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01}, +/* 70000000 < LCK/VCK < 100000000 will use this value */ +{DPA_CLK_RANGE_70_100M, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x03}, +/* 100000000 < LCK/VCK < 15000000 will use this value */ +{DPA_CLK_RANGE_100_150M, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02}, +/* 15000000 < LCK/VCK will use this value */ +{DPA_CLK_RANGE_150M, 0x00, 0x20, 0x00, 0x10, 0x00, 0x03, 0x00, 0x0D, 0x03}, +}; + +/* For VT3364: */ +struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3364[] = { +/* ClkRange,DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, + DVP1Driving, DFPHigh, DFPLow */ +/* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B, + SR65, CR97, CR99 */ +/* LCK/VCK < 30000000 will use this value */ +{DPA_CLK_RANGE_30M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, +/* 30000000 < LCK/VCK < 50000000 will use this value */ +{DPA_CLK_RANGE_30_50M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, +/* 50000000 < LCK/VCK < 70000000 will use this value */ +{DPA_CLK_RANGE_50_70M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, +/* 70000000 < LCK/VCK < 100000000 will use this value */ +{DPA_CLK_RANGE_70_100M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, +/* 100000000 < LCK/VCK < 15000000 will use this value */ +{DPA_CLK_RANGE_100_150M, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08}, +/* 15000000 < LCK/VCK will use this value */ +{DPA_CLK_RANGE_150M, 0x01, 0x00, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x08}, +}; diff --git a/drivers/video/via/tblDPASetting.h b/drivers/video/via/tblDPASetting.h new file mode 100644 index 00000000000..b065a83481d --- /dev/null +++ b/drivers/video/via/tblDPASetting.h @@ -0,0 +1,47 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _TBLDPASETTING_H_ +#define _TBLDPASETTING_H_ +#include "global.h" + +#define DPA_CLK_30M 30000000 +#define DPA_CLK_50M 50000000 +#define DPA_CLK_70M 70000000 +#define DPA_CLK_100M 100000000 +#define DPA_CLK_150M 150000000 + +enum DPA_RANGE { + DPA_CLK_RANGE_30M, + DPA_CLK_RANGE_30_50M, + DPA_CLK_RANGE_50_70M, + DPA_CLK_RANGE_70_100M, + DPA_CLK_RANGE_100_150M, + DPA_CLK_RANGE_150M +}; + +extern struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3324[7]; +extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3324[6]; +extern struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3327[7]; +extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3327[]; +extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3364[6]; + +#endif diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c new file mode 100644 index 00000000000..0f3ed4eb236 --- /dev/null +++ b/drivers/video/via/via_i2c.c @@ -0,0 +1,177 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" + +static void via_i2c_setscl(void *data, int state) +{ + u8 val; + struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data; + + val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0; + if (state) + val |= 0x20; + else + val &= ~0x20; + switch (via_i2c_chan->i2c_port) { + case I2CPORTINDEX: + val |= 0x01; + break; + case GPIOPORTINDEX: + val |= 0x80; + break; + default: + DEBUG_MSG("via_i2c: specify wrong i2c port.\n"); + } + viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val); +} + +static int via_i2c_getscl(void *data) +{ + struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data; + + if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x08) + return 1; + return 0; +} + +static int via_i2c_getsda(void *data) +{ + struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data; + + if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x04) + return 1; + return 0; +} + +static void via_i2c_setsda(void *data, int state) +{ + u8 val; + struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data; + + val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0; + if (state) + val |= 0x10; + else + val &= ~0x10; + switch (via_i2c_chan->i2c_port) { + case I2CPORTINDEX: + val |= 0x01; + break; + case GPIOPORTINDEX: + val |= 0x40; + break; + default: + DEBUG_MSG("via_i2c: specify wrong i2c port.\n"); + } + viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val); +} + +int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata) +{ + u8 mm1[] = {0x00}; + struct i2c_msg msgs[2]; + + *pdata = 0; + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + msgs[0].addr = msgs[1].addr = slave_addr / 2; + mm1[0] = index; + msgs[0].len = 1; msgs[1].len = 1; + msgs[0].buf = mm1; msgs[1].buf = pdata; + i2c_transfer(&viaparinfo->i2c_stuff.adapter, msgs, 2); + + return 0; +} + +int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data) +{ + u8 msg[2] = { index, data }; + struct i2c_msg msgs; + + msgs.flags = 0; + msgs.addr = slave_addr / 2; + msgs.len = 2; + msgs.buf = msg; + return i2c_transfer(&viaparinfo->i2c_stuff.adapter, &msgs, 1); +} + +int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len) +{ + u8 mm1[] = {0x00}; + struct i2c_msg msgs[2]; + + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + msgs[0].addr = msgs[1].addr = slave_addr / 2; + mm1[0] = index; + msgs[0].len = 1; msgs[1].len = buff_len; + msgs[0].buf = mm1; msgs[1].buf = buff; + i2c_transfer(&viaparinfo->i2c_stuff.adapter, msgs, 2); + return 0; +} + +int viafb_create_i2c_bus(void *viapar) +{ + int ret; + struct viafb_par *par = (struct viafb_par *)viapar; + + strcpy(par->i2c_stuff.adapter.name, "via_i2c"); + par->i2c_stuff.i2c_port = 0x0; + par->i2c_stuff.adapter.owner = THIS_MODULE; + par->i2c_stuff.adapter.id = 0x01FFFF; + par->i2c_stuff.adapter.class = 0; + par->i2c_stuff.adapter.algo_data = &par->i2c_stuff.algo; + par->i2c_stuff.adapter.dev.parent = NULL; + par->i2c_stuff.algo.setsda = via_i2c_setsda; + par->i2c_stuff.algo.setscl = via_i2c_setscl; + par->i2c_stuff.algo.getsda = via_i2c_getsda; + par->i2c_stuff.algo.getscl = via_i2c_getscl; + par->i2c_stuff.algo.udelay = 40; + par->i2c_stuff.algo.timeout = 20; + par->i2c_stuff.algo.data = &par->i2c_stuff; + + i2c_set_adapdata(&par->i2c_stuff.adapter, &par->i2c_stuff); + + /* Raise SCL and SDA */ + par->i2c_stuff.i2c_port = I2CPORTINDEX; + via_i2c_setsda(&par->i2c_stuff, 1); + via_i2c_setscl(&par->i2c_stuff, 1); + + par->i2c_stuff.i2c_port = GPIOPORTINDEX; + via_i2c_setsda(&par->i2c_stuff, 1); + via_i2c_setscl(&par->i2c_stuff, 1); + udelay(20); + + ret = i2c_bit_add_bus(&par->i2c_stuff.adapter); + if (ret == 0) + DEBUG_MSG("I2C bus %s registered.\n", + par->i2c_stuff.adapter.name); + else + DEBUG_MSG("Failed to register I2C bus %s.\n", + par->i2c_stuff.adapter.name); + return ret; +} + +void viafb_delete_i2c_buss(void *par) +{ + i2c_del_adapter(&((struct viafb_par *)par)->i2c_stuff.adapter); +} diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h new file mode 100644 index 00000000000..3a13242a315 --- /dev/null +++ b/drivers/video/via/via_i2c.h @@ -0,0 +1,46 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __VIA_I2C_H__ +#define __VIA_I2C_H__ + +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +struct via_i2c_stuff { + u16 i2c_port; /* GPIO or I2C port */ + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + +#define I2CPORT 0x3c4 +#define I2CPORTINDEX 0x31 +#define GPIOPORT 0x3C4 +#define GPIOPORTINDEX 0x2C +#define I2C_BUS 1 +#define GPIO_BUS 2 +#define DELAYPORT 0x3C3 + +int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata); +int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data); +int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len); +int viafb_create_i2c_bus(void *par); +void viafb_delete_i2c_buss(void *par); +#endif /* __VIA_I2C_H__ */ diff --git a/drivers/video/via/via_utility.c b/drivers/video/via/via_utility.c new file mode 100644 index 00000000000..d53c3d54ed8 --- /dev/null +++ b/drivers/video/via/via_utility.c @@ -0,0 +1,253 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" + +void viafb_get_device_support_state(u32 *support_state) +{ + *support_state = CRT_Device; + + if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name == VT1632_TMDS) + *support_state |= DVI_Device; + + if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name == VT1631_LVDS) + *support_state |= LCD_Device; +} + +void viafb_get_device_connect_state(u32 *connect_state) +{ + bool mobile = false; + + *connect_state = CRT_Device; + + if (viafb_dvi_sense()) + *connect_state |= DVI_Device; + + viafb_lcd_get_mobile_state(&mobile); + if (mobile) + *connect_state |= LCD_Device; +} + +bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres) +{ + unsigned int support_state = 0; + + switch (viafb_lcd_panel_id) { + case LCD_PANEL_ID0_640X480: + if ((xres < 640) && (yres < 480)) + support_state = true; + break; + + case LCD_PANEL_ID1_800X600: + if ((xres < 800) && (yres < 600)) + support_state = true; + break; + + case LCD_PANEL_ID2_1024X768: + if ((xres < 1024) && (yres < 768)) + support_state = true; + break; + + case LCD_PANEL_ID3_1280X768: + if ((xres < 1280) && (yres < 768)) + support_state = true; + break; + + case LCD_PANEL_ID4_1280X1024: + if ((xres < 1280) && (yres < 1024)) + support_state = true; + break; + + case LCD_PANEL_ID5_1400X1050: + if ((xres < 1400) && (yres < 1050)) + support_state = true; + break; + + case LCD_PANEL_ID6_1600X1200: + if ((xres < 1600) && (yres < 1200)) + support_state = true; + break; + + case LCD_PANEL_ID7_1366X768: + if ((xres < 1366) && (yres < 768)) + support_state = true; + break; + + case LCD_PANEL_ID8_1024X600: + if ((xres < 1024) && (yres < 600)) + support_state = true; + break; + + case LCD_PANEL_ID9_1280X800: + if ((xres < 1280) && (yres < 800)) + support_state = true; + break; + + case LCD_PANEL_IDA_800X480: + if ((xres < 800) && (yres < 480)) + support_state = true; + break; + + case LCD_PANEL_IDB_1360X768: + if ((xres < 1360) && (yres < 768)) + support_state = true; + break; + + case LCD_PANEL_IDC_480X640: + if ((xres < 480) && (yres < 640)) + support_state = true; + break; + + default: + support_state = false; + break; + } + + return support_state; +} + +/*====================================================================*/ +/* Gamma Function Implementation*/ +/*====================================================================*/ + +void viafb_set_gamma_table(int bpp, unsigned int *gamma_table) +{ + int i, sr1a; + int active_device_amount = 0; + int device_status = viafb_DeviceStatus; + + for (i = 0; i < sizeof(viafb_DeviceStatus) * 8; i++) { + if (device_status & 1) + active_device_amount++; + device_status >>= 1; + } + + /* 8 bpp mode can't adjust gamma */ + if (bpp == 8) + return ; + + /* Enable Gamma */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + viafb_write_reg_mask(SR16, VIASR, 0x80, BIT7); + break; + + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + case UNICHROME_CX700: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + case UNICHROME_P4M900: + viafb_write_reg_mask(CR33, VIACR, 0x80, BIT7); + break; + } + sr1a = (unsigned int)viafb_read_reg(VIASR, SR1A); + viafb_write_reg_mask(SR1A, VIASR, 0x0, BIT0); + + /* Fill IGA1 Gamma Table */ + outb(0, LUT_INDEX_WRITE); + for (i = 0; i < 256; i++) { + outb(gamma_table[i] >> 16, LUT_DATA); + outb(gamma_table[i] >> 8 & 0xFF, LUT_DATA); + outb(gamma_table[i] & 0xFF, LUT_DATA); + } + + /* If adjust Gamma value in SAMM, fill IGA1, + IGA2 Gamma table simultanous. */ + /* Switch to IGA2 Gamma Table */ + if ((active_device_amount > 1) && + !((viaparinfo->chip_info->gfx_chip_name == + UNICHROME_CLE266) && + (viaparinfo->chip_info->gfx_chip_revision < 15))) { + viafb_write_reg_mask(SR1A, VIASR, 0x01, BIT0); + viafb_write_reg_mask(CR6A, VIACR, 0x02, BIT1); + + /* Fill IGA2 Gamma Table */ + outb(0, LUT_INDEX_WRITE); + for (i = 0; i < 256; i++) { + outb(gamma_table[i] >> 16, LUT_DATA); + outb(gamma_table[i] >> 8 & 0xFF, LUT_DATA); + outb(gamma_table[i] & 0xFF, LUT_DATA); + } + } + viafb_write_reg(SR1A, VIASR, sr1a); +} + +void viafb_get_gamma_table(unsigned int *gamma_table) +{ + unsigned char color_r, color_g, color_b; + unsigned char sr1a = 0; + int i; + + /* Enable Gamma */ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_CLE266: + case UNICHROME_K400: + viafb_write_reg_mask(SR16, VIASR, 0x80, BIT7); + break; + + case UNICHROME_K800: + case UNICHROME_PM800: + case UNICHROME_CN700: + case UNICHROME_CX700: + case UNICHROME_K8M890: + case UNICHROME_P4M890: + case UNICHROME_P4M900: + viafb_write_reg_mask(CR33, VIACR, 0x80, BIT7); + break; + } + sr1a = viafb_read_reg(VIASR, SR1A); + viafb_write_reg_mask(SR1A, VIASR, 0x0, BIT0); + + /* Reading gamma table to get color value */ + outb(0, LUT_INDEX_READ); + for (i = 0; i < 256; i++) { + color_r = inb(LUT_DATA); + color_g = inb(LUT_DATA); + color_b = inb(LUT_DATA); + gamma_table[i] = + ((((u32) color_r) << 16) | + (((u16) color_g) << 8)) | color_b; + } + viafb_write_reg(SR1A, VIASR, sr1a); +} + +void viafb_get_gamma_support_state(int bpp, unsigned int *support_state) +{ + if (bpp == 8) + *support_state = None_Device; + else + *support_state = CRT_Device | DVI_Device | LCD_Device; +} + +int viafb_input_parameter_converter(int parameter_value) +{ + int result; + + if (parameter_value >= 1 && parameter_value <= 9) + result = 1 << (parameter_value - 1); + else + result = 1; + + return result; +} diff --git a/drivers/video/via/via_utility.h b/drivers/video/via/via_utility.h new file mode 100644 index 00000000000..2fd455202eb --- /dev/null +++ b/drivers/video/via/via_utility.h @@ -0,0 +1,35 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __VIAUTILITY_H__ +#define __VIAUTILITY_H__ + +/* These functions are used to get infomation about device's state */ +void viafb_get_device_support_state(u32 *support_state); +void viafb_get_device_connect_state(u32 *connect_state); +bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres); + +/* These function are used to access gamma table */ +void viafb_set_gamma_table(int bpp, unsigned int *gamma_table); +void viafb_get_gamma_table(unsigned int *gamma_table); +void viafb_get_gamma_support_state(int bpp, unsigned int *support_state); +int viafb_input_parameter_converter(int parameter_value); + +#endif /* __VIAUTILITY_H__ */ diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c new file mode 100644 index 00000000000..0132eae06f5 --- /dev/null +++ b/drivers/video/via/viafbdev.c @@ -0,0 +1,2571 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/module.h> +#define _MASTER_FILE + +#include "global.h" + +static int MAX_CURS = 32; +static struct fb_var_screeninfo default_var; +static char *viafb_name = "Via"; +static u32 pseudo_pal[17]; + +/* video mode */ +static char *viafb_mode = "640x480"; +static char *viafb_mode1 = "640x480"; +static int viafb_resMode = VIA_RES_640X480; + +/* Added for specifying active devices.*/ +char *viafb_active_dev = ""; + +/* Added for specifying video on devices.*/ +char *viafb_video_dev = ""; + +/*Added for specify lcd output port*/ +char *viafb_lcd_port = ""; +char *viafb_dvi_port = ""; + +static void viafb_set_device(struct device_t active_dev); +static int apply_device_setting(struct viafb_ioctl_setting setting_info, + struct fb_info *info); +static void apply_second_mode_setting(struct fb_var_screeninfo + *sec_var); +static void retrieve_device_setting(struct viafb_ioctl_setting + *setting_info); +static void viafb_set_video_device(u32 video_dev_info); +static void viafb_get_video_device(u32 *video_dev_info); + +/* Mode information */ +static const struct viafb_modeinfo viafb_modentry[] = { + {480, 640, VIA_RES_480X640, "480x640"}, + {640, 480, VIA_RES_640X480, "640x480"}, + {800, 480, VIA_RES_800X480, "800x480"}, + {800, 600, VIA_RES_800X600, "800x600"}, + {1024, 768, VIA_RES_1024X768, "1024x768"}, + {1152, 864, VIA_RES_1152X864, "1152x864"}, + {1280, 1024, VIA_RES_1280X1024, "1280x1024"}, + {1600, 1200, VIA_RES_1600X1200, "1600x1200"}, + {1440, 1050, VIA_RES_1440X1050, "1440x1050"}, + {1280, 768, VIA_RES_1280X768, "1280x768"}, + {1280, 800, VIA_RES_1280X800, "1280x800"}, + {1280, 960, VIA_RES_1280X960, "1280x960"}, + {1920, 1440, VIA_RES_1920X1440, "1920x1440"}, + {848, 480, VIA_RES_848X480, "848x480"}, + {1400, 1050, VIA_RES_1400X1050, "1400x1050"}, + {720, 480, VIA_RES_720X480, "720x480"}, + {720, 576, VIA_RES_720X576, "720x576"}, + {1024, 512, VIA_RES_1024X512, "1024x512"}, + {1024, 576, VIA_RES_1024X576, "1024x576"}, + {1024, 600, VIA_RES_1024X600, "1024x600"}, + {1280, 720, VIA_RES_1280X720, "1280x720"}, + {1920, 1080, VIA_RES_1920X1080, "1920x1080"}, + {1366, 768, VIA_RES_1368X768, "1368x768"}, + {1680, 1050, VIA_RES_1680X1050, "1680x1050"}, + {960, 600, VIA_RES_960X600, "960x600"}, + {1000, 600, VIA_RES_1000X600, "1000x600"}, + {1024, 576, VIA_RES_1024X576, "1024x576"}, + {1024, 600, VIA_RES_1024X600, "1024x600"}, + {1088, 612, VIA_RES_1088X612, "1088x612"}, + {1152, 720, VIA_RES_1152X720, "1152x720"}, + {1200, 720, VIA_RES_1200X720, "1200x720"}, + {1280, 600, VIA_RES_1280X600, "1280x600"}, + {1360, 768, VIA_RES_1360X768, "1360x768"}, + {1440, 900, VIA_RES_1440X900, "1440x900"}, + {1600, 900, VIA_RES_1600X900, "1600x900"}, + {1600, 1024, VIA_RES_1600X1024, "1600x1024"}, + {1792, 1344, VIA_RES_1792X1344, "1792x1344"}, + {1856, 1392, VIA_RES_1856X1392, "1856x1392"}, + {1920, 1200, VIA_RES_1920X1200, "1920x1200"}, + {2048, 1536, VIA_RES_2048X1536, "2048x1536"}, + {0, 0, VIA_RES_INVALID, "640x480"} +}; + +static struct fb_ops viafb_ops; + +static int viafb_update_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) +{ + struct viafb_par *ppar; + ppar = info->par; + + DEBUG_MSG(KERN_INFO "viafb_update_fix!\n"); + + fix->visual = + ppar->bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + fix->line_length = ppar->linelength; + + return 0; +} + + +static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix, + struct viafb_par *viaparinfo) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, viafb_name); + + fix->smem_start = viaparinfo->fbmem; + fix->smem_len = viaparinfo->fbmem_free; + fix->mmio_start = viaparinfo->mmio_base; + fix->mmio_len = viaparinfo->mmio_len; + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + + fix->xpanstep = fix->ywrapstep = 0; + fix->ypanstep = 1; + + /* Just tell the accel name */ + viafbinfo->fix.accel = FB_ACCEL_VIA_UNICHROME; +} +static int viafb_open(struct fb_info *info, int user) +{ + DEBUG_MSG(KERN_INFO "viafb_open!\n"); + return 0; +} + +static int viafb_release(struct fb_info *info, int user) +{ + DEBUG_MSG(KERN_INFO "viafb_release!\n"); + return 0; +} + +static void viafb_update_viafb_par(struct fb_info *info) +{ + struct viafb_par *ppar; + + ppar = info->par; + ppar->bpp = info->var.bits_per_pixel; + ppar->linelength = ((info->var.xres_virtual + 7) & ~7) * ppar->bpp / 8; + ppar->hres = info->var.xres; + ppar->vres = info->var.yres; + ppar->xoffset = info->var.xoffset; + ppar->yoffset = info->var.yoffset; +} + +static int viafb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int vmode_index, htotal, vtotal; + struct viafb_par *ppar; + u32 long_refresh; + struct viafb_par *p_viafb_par; + ppar = info->par; + + + DEBUG_MSG(KERN_INFO "viafb_check_var!\n"); + /* Sanity check */ + /* HW neither support interlacte nor double-scaned mode */ + if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE) + return -EINVAL; + + vmode_index = viafb_get_mode_index(var->xres, var->yres, 0); + if (vmode_index == VIA_RES_INVALID) { + DEBUG_MSG(KERN_INFO + "viafb: Mode %dx%dx%d not supported!!\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } + + if (24 == var->bits_per_pixel) + var->bits_per_pixel = 32; + + if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 && + var->bits_per_pixel != 32) + return -EINVAL; + + if ((var->xres_virtual * (var->bits_per_pixel >> 3)) & 0x1F) + /*32 pixel alignment */ + var->xres_virtual = (var->xres_virtual + 31) & ~31; + if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > + ppar->memsize) + return -EINVAL; + + /* Based on var passed in to calculate the refresh, + * because our driver use some modes special. + */ + htotal = var->xres + var->left_margin + + var->right_margin + var->hsync_len; + vtotal = var->yres + var->upper_margin + + var->lower_margin + var->vsync_len; + long_refresh = 1000000000UL / var->pixclock * 1000; + long_refresh /= (htotal * vtotal); + + viafb_refresh = viafb_get_refresh(var->xres, var->yres, long_refresh); + + /* Adjust var according to our driver's own table */ + viafb_fill_var_timing_info(var, viafb_refresh, vmode_index); + + /* This is indeed a patch for VT3353 */ + if (!info->par) + return -1; + p_viafb_par = (struct viafb_par *)info->par; + if (p_viafb_par->chip_info->gfx_chip_name == UNICHROME_VX800) + var->accel_flags = 0; + + return 0; +} + +static int viafb_set_par(struct fb_info *info) +{ + int vmode_index; + int vmode_index1 = 0; + DEBUG_MSG(KERN_INFO "viafb_set_par!\n"); + + viafb_update_device_setting(info->var.xres, info->var.yres, + info->var.bits_per_pixel, viafb_refresh, 0); + + vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres, 0); + + if (viafb_SAMM_ON == 1) { + DEBUG_MSG(KERN_INFO + "viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n", + viafb_second_xres, viafb_second_yres, viafb_bpp1); + vmode_index1 = viafb_get_mode_index(viafb_second_xres, + viafb_second_yres, 1); + DEBUG_MSG(KERN_INFO "->viafb_SAMM_ON: index=%d\n", + vmode_index1); + + viafb_update_device_setting(viafb_second_xres, + viafb_second_yres, viafb_bpp1, viafb_refresh1, 1); + } + + if (vmode_index != VIA_RES_INVALID) { + viafb_setmode(vmode_index, info->var.xres, info->var.yres, + info->var.bits_per_pixel, vmode_index1, + viafb_second_xres, viafb_second_yres, viafb_bpp1); + + /*We should set memory offset according virtual_x */ + /*Fix me:put this function into viafb_setmode */ + viafb_memory_pitch_patch(info); + + /* Update ***fb_par information */ + viafb_update_viafb_par(info); + + /* Update other fixed information */ + viafb_update_fix(&info->fix, info); + viafb_bpp = info->var.bits_per_pixel; + /* Update viafb_accel, it is necessary to our 2D accelerate */ + viafb_accel = info->var.accel_flags; + + if (viafb_accel) + viafb_set_2d_color_depth(info->var.bits_per_pixel); + } + + return 0; +} + +/* Set one color register */ +static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green, +unsigned blue, unsigned transp, struct fb_info *info) +{ + u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10; + unsigned cmap_entries = (info->var.bits_per_pixel == 8) ? 256 : 16; + DEBUG_MSG(KERN_INFO "viafb_setcolreg!\n"); + if (regno >= cmap_entries) + return 1; + if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) { + /* + * Read PCI bus 0,dev 0,function 0,index 0xF6 to get chip rev. + */ + outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8); + rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff; + } + switch (info->var.bits_per_pixel) { + case 8: + outb(0x1A, 0x3C4); + sr1a = inb(0x3C5); + outb(0x1B, 0x3C4); + sr1b = inb(0x3C5); + outb(0x67, 0x3D4); + cr67 = inb(0x3D5); + outb(0x6A, 0x3D4); + cr6a = inb(0x3D5); + + /* Map the 3C6/7/8/9 to the IGA2 */ + outb(0x1A, 0x3C4); + outb(sr1a | 0x01, 0x3C5); + /* Second Display Engine colck always on */ + outb(0x1B, 0x3C4); + outb(sr1b | 0x80, 0x3C5); + /* Second Display Color Depth 8 */ + outb(0x67, 0x3D4); + outb(cr67 & 0x3F, 0x3D5); + outb(0x6A, 0x3D4); + /* Second Display Channel Reset CR6A[6]) */ + outb(cr6a & 0xBF, 0x3D5); + /* Second Display Channel Enable CR6A[7] */ + outb(cr6a | 0x80, 0x3D5); + /* Second Display Channel stop reset) */ + outb(cr6a | 0x40, 0x3D5); + + /* Bit mask of palette */ + outb(0xFF, 0x3c6); + /* Write one register of IGA2 */ + outb(regno, 0x3C8); + if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name && + rev >= 15) { + shift = 8; + viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5); + viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7); + } else { + shift = 10; + viafb_write_reg_mask(CR6A, VIACR, 0, BIT5); + viafb_write_reg_mask(SR15, VIASR, 0, BIT7); + } + outb(red >> shift, 0x3C9); + outb(green >> shift, 0x3C9); + outb(blue >> shift, 0x3C9); + + /* Map the 3C6/7/8/9 to the IGA1 */ + outb(0x1A, 0x3C4); + outb(sr1a & 0xFE, 0x3C5); + /* Bit mask of palette */ + outb(0xFF, 0x3c6); + /* Write one register of IGA1 */ + outb(regno, 0x3C8); + outb(red >> shift, 0x3C9); + outb(green >> shift, 0x3C9); + outb(blue >> shift, 0x3C9); + + outb(0x1A, 0x3C4); + outb(sr1a, 0x3C5); + outb(0x1B, 0x3C4); + outb(sr1b, 0x3C5); + outb(0x67, 0x3D4); + outb(cr67, 0x3D5); + outb(0x6A, 0x3D4); + outb(cr6a, 0x3D5); + break; + case 16: + ((u32 *) info->pseudo_palette)[regno] = (red & 0xF800) | + ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); + break; + case 32: + ((u32 *) info->pseudo_palette)[regno] = + ((transp & 0xFF00) << 16) | + ((red & 0xFF00) << 8) | + ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); + break; + } + + return 0; + +} + +/*CALLED BY: fb_set_cmap */ +/* fb_set_var, pass 256 colors */ +/*CALLED BY: fb_set_cmap */ +/* fbcon_set_palette, pass 16 colors */ +static int viafb_setcmap(struct fb_cmap *cmap, struct fb_info *info) +{ + u32 len = cmap->len; + u32 i; + u16 *pred = cmap->red; + u16 *pgreen = cmap->green; + u16 *pblue = cmap->blue; + u16 *ptransp = cmap->transp; + u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10; + if (len > 256) + return 1; + if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) { + /* + * Read PCI bus 0, dev 0, function 0, index 0xF6 to get chip + * rev. + */ + outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8); + rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff; + } + switch (info->var.bits_per_pixel) { + case 8: + outb(0x1A, 0x3C4); + sr1a = inb(0x3C5); + outb(0x1B, 0x3C4); + sr1b = inb(0x3C5); + outb(0x67, 0x3D4); + cr67 = inb(0x3D5); + outb(0x6A, 0x3D4); + cr6a = inb(0x3D5); + /* Map the 3C6/7/8/9 to the IGA2 */ + outb(0x1A, 0x3C4); + outb(sr1a | 0x01, 0x3C5); + outb(0x1B, 0x3C4); + /* Second Display Engine colck always on */ + outb(sr1b | 0x80, 0x3C5); + outb(0x67, 0x3D4); + /* Second Display Color Depth 8 */ + outb(cr67 & 0x3F, 0x3D5); + outb(0x6A, 0x3D4); + /* Second Display Channel Reset CR6A[6]) */ + outb(cr6a & 0xBF, 0x3D5); + /* Second Display Channel Enable CR6A[7] */ + outb(cr6a | 0x80, 0x3D5); + /* Second Display Channel stop reset) */ + outb(cr6a | 0xC0, 0x3D5); + + /* Bit mask of palette */ + outb(0xFF, 0x3c6); + outb(0x00, 0x3C8); + if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name && + rev >= 15) { + shift = 8; + viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5); + viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7); + } else { + shift = 10; + viafb_write_reg_mask(CR6A, VIACR, 0, BIT5); + viafb_write_reg_mask(SR15, VIASR, 0, BIT7); + } + for (i = 0; i < len; i++) { + outb((*(pred + i)) >> shift, 0x3C9); + outb((*(pgreen + i)) >> shift, 0x3C9); + outb((*(pblue + i)) >> shift, 0x3C9); + } + + outb(0x1A, 0x3C4); + /* Map the 3C6/7/8/9 to the IGA1 */ + outb(sr1a & 0xFE, 0x3C5); + /* Bit mask of palette */ + outb(0xFF, 0x3c6); + outb(0x00, 0x3C8); + for (i = 0; i < len; i++) { + outb((*(pred + i)) >> shift, 0x3C9); + outb((*(pgreen + i)) >> shift, 0x3C9); + outb((*(pblue + i)) >> shift, 0x3C9); + } + + outb(0x1A, 0x3C4); + outb(sr1a, 0x3C5); + outb(0x1B, 0x3C4); + outb(sr1b, 0x3C5); + outb(0x67, 0x3D4); + outb(cr67, 0x3D5); + outb(0x6A, 0x3D4); + outb(cr6a, 0x3D5); + break; + case 16: + if (len > 17) + return 0; /* Because static u32 pseudo_pal[17]; */ + for (i = 0; i < len; i++) + ((u32 *) info->pseudo_palette)[i] = + (*(pred + i) & 0xF800) | + ((*(pgreen + i) & 0xFC00) >> 5) | + ((*(pblue + i) & 0xF800) >> 11); + break; + case 32: + if (len > 17) + return 0; + if (ptransp) { + for (i = 0; i < len; i++) + ((u32 *) info->pseudo_palette)[i] = + ((*(ptransp + i) & 0xFF00) << 16) | + ((*(pred + i) & 0xFF00) << 8) | + ((*(pgreen + i) & 0xFF00)) | + ((*(pblue + i) & 0xFF00) >> 8); + } else { + for (i = 0; i < len; i++) + ((u32 *) info->pseudo_palette)[i] = + 0x00000000 | + ((*(pred + i) & 0xFF00) << 8) | + ((*(pgreen + i) & 0xFF00)) | + ((*(pblue + i) & 0xFF00) >> 8); + } + break; + } + return 0; +} + +static int viafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned int offset; + + DEBUG_MSG(KERN_INFO "viafb_pan_display!\n"); + + offset = (var->xoffset + (var->yoffset * var->xres_virtual)) * + var->bits_per_pixel / 16; + + DEBUG_MSG(KERN_INFO "\nviafb_pan_display,offset =%d ", offset); + + viafb_write_reg_mask(0x48, 0x3d4, ((offset >> 24) & 0x3), 0x3); + viafb_write_reg_mask(0x34, 0x3d4, ((offset >> 16) & 0xff), 0xff); + viafb_write_reg_mask(0x0c, 0x3d4, ((offset >> 8) & 0xff), 0xff); + viafb_write_reg_mask(0x0d, 0x3d4, (offset & 0xff), 0xff); + + return 0; +} + +static int viafb_blank(int blank_mode, struct fb_info *info) +{ + DEBUG_MSG(KERN_INFO "viafb_blank!\n"); + /* clear DPMS setting */ + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + /* Screen: On, HSync: On, VSync: On */ + /* control CRT monitor power management */ + viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5); + break; + case FB_BLANK_HSYNC_SUSPEND: + /* Screen: Off, HSync: Off, VSync: On */ + /* control CRT monitor power management */ + viafb_write_reg_mask(CR36, VIACR, 0x10, BIT4 + BIT5); + break; + case FB_BLANK_VSYNC_SUSPEND: + /* Screen: Off, HSync: On, VSync: Off */ + /* control CRT monitor power management */ + viafb_write_reg_mask(CR36, VIACR, 0x20, BIT4 + BIT5); + break; + case FB_BLANK_POWERDOWN: + /* Screen: Off, HSync: Off, VSync: Off */ + /* control CRT monitor power management */ + viafb_write_reg_mask(CR36, VIACR, 0x30, BIT4 + BIT5); + break; + } + + return 0; +} + +static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) +{ + struct viafb_ioctl_mode viamode; + struct viafb_ioctl_samm viasamm; + struct viafb_driver_version driver_version; + struct fb_var_screeninfo sec_var; + struct _panel_size_pos_info panel_pos_size_para; + u32 state_info = 0; + u32 viainfo_size = sizeof(struct viafb_ioctl_info); + u32 *viafb_gamma_table; + char driver_name[] = "viafb"; + + u32 __user *argp = (u32 __user *) arg; + u32 gpu32; + u32 video_dev_info = 0; + struct viafb_ioctl_setting viafb_setting = {}; + struct device_t active_dev = {}; + + DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd); + + switch (cmd) { + case VIAFB_GET_CHIP_INFO: + if (copy_to_user(argp, viaparinfo->chip_info, + sizeof(struct chip_information))) + return -EFAULT; + break; + case VIAFB_GET_INFO_SIZE: + return put_user(viainfo_size, argp); + case VIAFB_GET_INFO: + return viafb_ioctl_get_viafb_info(arg); + case VIAFB_HOTPLUG: + return put_user(viafb_ioctl_hotplug(info->var.xres, + info->var.yres, + info->var.bits_per_pixel), argp); + case VIAFB_SET_HOTPLUG_FLAG: + if (copy_from_user(&gpu32, argp, sizeof(gpu32))) + return -EFAULT; + viafb_hotplug = (gpu32) ? 1 : 0; + break; + case VIAFB_GET_RESOLUTION: + viamode.xres = (u32) viafb_hotplug_Xres; + viamode.yres = (u32) viafb_hotplug_Yres; + viamode.refresh = (u32) viafb_hotplug_refresh; + viamode.bpp = (u32) viafb_hotplug_bpp; + if (viafb_SAMM_ON == 1) { + viamode.xres_sec = viafb_second_xres; + viamode.yres_sec = viafb_second_yres; + viamode.virtual_xres_sec = viafb_second_virtual_xres; + viamode.virtual_yres_sec = viafb_second_virtual_yres; + viamode.refresh_sec = viafb_refresh1; + viamode.bpp_sec = viafb_bpp1; + } else { + viamode.xres_sec = 0; + viamode.yres_sec = 0; + viamode.virtual_xres_sec = 0; + viamode.virtual_yres_sec = 0; + viamode.refresh_sec = 0; + viamode.bpp_sec = 0; + } + if (copy_to_user(argp, &viamode, sizeof(viamode))) + return -EFAULT; + break; + case VIAFB_GET_SAMM_INFO: + viasamm.samm_status = viafb_SAMM_ON; + + if (viafb_SAMM_ON == 1) { + if (viafb_dual_fb) { + viasamm.size_prim = viaparinfo->fbmem_free; + viasamm.size_sec = viaparinfo1->fbmem_free; + } else { + if (viafb_second_size) { + viasamm.size_prim = + viaparinfo->fbmem_free - + viafb_second_size * 1024 * 1024; + viasamm.size_sec = + viafb_second_size * 1024 * 1024; + } else { + viasamm.size_prim = + viaparinfo->fbmem_free >> 1; + viasamm.size_sec = + (viaparinfo->fbmem_free >> 1); + } + } + viasamm.mem_base = viaparinfo->fbmem; + viasamm.offset_sec = viafb_second_offset; + } else { + viasamm.size_prim = + viaparinfo->memsize - viaparinfo->fbmem_used; + viasamm.size_sec = 0; + viasamm.mem_base = viaparinfo->fbmem; + viasamm.offset_sec = 0; + } + + if (copy_to_user(argp, &viasamm, sizeof(viasamm))) + return -EFAULT; + + break; + case VIAFB_TURN_ON_OUTPUT_DEVICE: + if (copy_from_user(&gpu32, argp, sizeof(gpu32))) + return -EFAULT; + if (gpu32 & CRT_Device) + viafb_crt_enable(); + if (gpu32 & DVI_Device) + viafb_dvi_enable(); + if (gpu32 & LCD_Device) + viafb_lcd_enable(); + break; + case VIAFB_TURN_OFF_OUTPUT_DEVICE: + if (copy_from_user(&gpu32, argp, sizeof(gpu32))) + return -EFAULT; + if (gpu32 & CRT_Device) + viafb_crt_disable(); + if (gpu32 & DVI_Device) + viafb_dvi_disable(); + if (gpu32 & LCD_Device) + viafb_lcd_disable(); + break; + case VIAFB_SET_DEVICE: + if (copy_from_user(&active_dev, (void *)argp, + sizeof(active_dev))) + return -EFAULT; + viafb_set_device(active_dev); + viafb_set_par(info); + break; + case VIAFB_GET_DEVICE: + active_dev.crt = viafb_CRT_ON; + active_dev.dvi = viafb_DVI_ON; + active_dev.lcd = viafb_LCD_ON; + active_dev.samm = viafb_SAMM_ON; + active_dev.primary_dev = viafb_primary_dev; + + active_dev.lcd_dsp_cent = viafb_lcd_dsp_method; + active_dev.lcd_panel_id = viafb_lcd_panel_id; + active_dev.lcd_mode = viafb_lcd_mode; + + active_dev.xres = viafb_hotplug_Xres; + active_dev.yres = viafb_hotplug_Yres; + + active_dev.xres1 = viafb_second_xres; + active_dev.yres1 = viafb_second_yres; + + active_dev.bpp = viafb_bpp; + active_dev.bpp1 = viafb_bpp1; + active_dev.refresh = viafb_refresh; + active_dev.refresh1 = viafb_refresh1; + + active_dev.epia_dvi = viafb_platform_epia_dvi; + active_dev.lcd_dual_edge = viafb_device_lcd_dualedge; + active_dev.bus_width = viafb_bus_width; + + if (copy_to_user(argp, &active_dev, sizeof(active_dev))) + return -EFAULT; + break; + + case VIAFB_GET_DRIVER_VERSION: + driver_version.iMajorNum = VERSION_MAJOR; + driver_version.iKernelNum = VERSION_KERNEL; + driver_version.iOSNum = VERSION_OS; + driver_version.iMinorNum = VERSION_MINOR; + + if (copy_to_user(argp, &driver_version, + sizeof(driver_version))) + return -EFAULT; + + break; + + case VIAFB_SET_DEVICE_INFO: + if (copy_from_user(&viafb_setting, + argp, sizeof(viafb_setting))) + return -EFAULT; + if (apply_device_setting(viafb_setting, info) < 0) + return -EINVAL; + + break; + + case VIAFB_SET_SECOND_MODE: + if (copy_from_user(&sec_var, argp, sizeof(sec_var))) + return -EFAULT; + apply_second_mode_setting(&sec_var); + break; + + case VIAFB_GET_DEVICE_INFO: + + retrieve_device_setting(&viafb_setting); + + if (copy_to_user(argp, &viafb_setting, sizeof(viafb_setting))) + return -EFAULT; + + break; + + case VIAFB_GET_DEVICE_SUPPORT: + viafb_get_device_support_state(&state_info); + if (put_user(state_info, argp)) + return -EFAULT; + break; + + case VIAFB_GET_DEVICE_CONNECT: + viafb_get_device_connect_state(&state_info); + if (put_user(state_info, argp)) + return -EFAULT; + break; + + case VIAFB_GET_PANEL_SUPPORT_EXPAND: + state_info = + viafb_lcd_get_support_expand_state(info->var.xres, + info->var.yres); + if (put_user(state_info, argp)) + return -EFAULT; + break; + + case VIAFB_GET_DRIVER_NAME: + if (copy_to_user(argp, driver_name, sizeof(driver_name))) + return -EFAULT; + break; + + case VIAFB_SET_GAMMA_LUT: + viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL); + if (!viafb_gamma_table) + return -ENOMEM; + if (copy_from_user(viafb_gamma_table, argp, + sizeof(viafb_gamma_table))) { + kfree(viafb_gamma_table); + return -EFAULT; + } + viafb_set_gamma_table(viafb_bpp, viafb_gamma_table); + kfree(viafb_gamma_table); + break; + + case VIAFB_GET_GAMMA_LUT: + viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL); + if (!viafb_gamma_table) + return -ENOMEM; + viafb_get_gamma_table(viafb_gamma_table); + if (copy_to_user(argp, viafb_gamma_table, + sizeof(viafb_gamma_table))) { + kfree(viafb_gamma_table); + return -EFAULT; + } + kfree(viafb_gamma_table); + break; + + case VIAFB_GET_GAMMA_SUPPORT_STATE: + viafb_get_gamma_support_state(viafb_bpp, &state_info); + if (put_user(state_info, argp)) + return -EFAULT; + break; + case VIAFB_SET_VIDEO_DEVICE: + get_user(video_dev_info, argp); + viafb_set_video_device(video_dev_info); + break; + case VIAFB_GET_VIDEO_DEVICE: + viafb_get_video_device(&video_dev_info); + if (put_user(video_dev_info, argp)) + return -EFAULT; + break; + case VIAFB_SYNC_SURFACE: + DEBUG_MSG(KERN_INFO "lobo VIAFB_SYNC_SURFACE\n"); + break; + case VIAFB_GET_DRIVER_CAPS: + break; + + case VIAFB_GET_PANEL_MAX_SIZE: + if (copy_from_user + (&panel_pos_size_para, argp, sizeof(panel_pos_size_para))) + return -EFAULT; + panel_pos_size_para.x = panel_pos_size_para.y = 0; + if (copy_to_user(argp, &panel_pos_size_para, + sizeof(panel_pos_size_para))) + return -EFAULT; + break; + case VIAFB_GET_PANEL_MAX_POSITION: + if (copy_from_user + (&panel_pos_size_para, argp, sizeof(panel_pos_size_para))) + return -EFAULT; + panel_pos_size_para.x = panel_pos_size_para.y = 0; + if (copy_to_user(argp, &panel_pos_size_para, + sizeof(panel_pos_size_para))) + return -EFAULT; + break; + + case VIAFB_GET_PANEL_POSITION: + if (copy_from_user + (&panel_pos_size_para, argp, sizeof(panel_pos_size_para))) + return -EFAULT; + panel_pos_size_para.x = panel_pos_size_para.y = 0; + if (copy_to_user(argp, &panel_pos_size_para, + sizeof(panel_pos_size_para))) + return -EFAULT; + break; + case VIAFB_GET_PANEL_SIZE: + if (copy_from_user + (&panel_pos_size_para, argp, sizeof(panel_pos_size_para))) + return -EFAULT; + panel_pos_size_para.x = panel_pos_size_para.y = 0; + if (copy_to_user(argp, &panel_pos_size_para, + sizeof(panel_pos_size_para))) + return -EFAULT; + break; + + case VIAFB_SET_PANEL_POSITION: + if (copy_from_user + (&panel_pos_size_para, argp, sizeof(panel_pos_size_para))) + return -EFAULT; + break; + case VIAFB_SET_PANEL_SIZE: + if (copy_from_user + (&panel_pos_size_para, argp, sizeof(panel_pos_size_para))) + return -EFAULT; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static void viafb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + u32 col = 0, rop = 0; + int pitch; + + if (!viafb_accel) + return cfb_fillrect(info, rect); + + if (!rect->width || !rect->height) + return; + + switch (rect->rop) { + case ROP_XOR: + rop = 0x5A; + break; + case ROP_COPY: + default: + rop = 0xF0; + break; + } + + switch (info->var.bits_per_pixel) { + case 8: + col = rect->color; + break; + case 16: + col = ((u32 *) (info->pseudo_palette))[rect->color]; + break; + case 32: + col = ((u32 *) (info->pseudo_palette))[rect->color]; + break; + } + + /* BitBlt Source Address */ + writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS); + /* Source Base Address */ + writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE); + /* Destination Base Address */ + writel(((unsigned long) (info->screen_base) - + (unsigned long) viafb_FB_MM) >> 3, + viaparinfo->io_virt + VIA_REG_DSTBASE); + /* Pitch */ + pitch = (info->var.xres_virtual + 7) & ~7; + writel(VIA_PITCH_ENABLE | + (((pitch * + info->var.bits_per_pixel >> 3) >> 3) | + (((pitch * info-> + var.bits_per_pixel >> 3) >> 3) << 16)), + viaparinfo->io_virt + VIA_REG_PITCH); + /* BitBlt Destination Address */ + writel(((rect->dy << 16) | rect->dx), + viaparinfo->io_virt + VIA_REG_DSTPOS); + /* Dimension: width & height */ + writel((((rect->height - 1) << 16) | (rect->width - 1)), + viaparinfo->io_virt + VIA_REG_DIMENSION); + /* Forground color or Destination color */ + writel(col, viaparinfo->io_virt + VIA_REG_FGCOLOR); + /* GE Command */ + writel((0x01 | 0x2000 | (rop << 24)), + viaparinfo->io_virt + VIA_REG_GECMD); + +} + +static void viafb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + u32 dy = area->dy, sy = area->sy, direction = 0x0; + u32 sx = area->sx, dx = area->dx, width = area->width; + int pitch; + + DEBUG_MSG(KERN_INFO "viafb_copyarea!!\n"); + + if (!viafb_accel) + return cfb_copyarea(info, area); + + if (!area->width || !area->height) + return; + + if (sy < dy) { + dy += area->height - 1; + sy += area->height - 1; + direction |= 0x4000; + } + + if (sx < dx) { + dx += width - 1; + sx += width - 1; + direction |= 0x8000; + } + + /* Source Base Address */ + writel(((unsigned long) (info->screen_base) - + (unsigned long) viafb_FB_MM) >> 3, + viaparinfo->io_virt + VIA_REG_SRCBASE); + /* Destination Base Address */ + writel(((unsigned long) (info->screen_base) - + (unsigned long) viafb_FB_MM) >> 3, + viaparinfo->io_virt + VIA_REG_DSTBASE); + /* Pitch */ + pitch = (info->var.xres_virtual + 7) & ~7; + /* VIA_PITCH_ENABLE can be omitted now. */ + writel(VIA_PITCH_ENABLE | + (((pitch * + info->var.bits_per_pixel >> 3) >> 3) | (((pitch * + info->var. + bits_per_pixel + >> 3) >> 3) + << 16)), + viaparinfo->io_virt + VIA_REG_PITCH); + /* BitBlt Source Address */ + writel(((sy << 16) | sx), viaparinfo->io_virt + VIA_REG_SRCPOS); + /* BitBlt Destination Address */ + writel(((dy << 16) | dx), viaparinfo->io_virt + VIA_REG_DSTPOS); + /* Dimension: width & height */ + writel((((area->height - 1) << 16) | (area->width - 1)), + viaparinfo->io_virt + VIA_REG_DIMENSION); + /* GE Command */ + writel((0x01 | direction | (0xCC << 24)), + viaparinfo->io_virt + VIA_REG_GECMD); + +} + +static void viafb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + u32 size, bg_col = 0, fg_col = 0, *udata; + int i; + int pitch; + + if (!viafb_accel) + return cfb_imageblit(info, image); + + udata = (u32 *) image->data; + + switch (info->var.bits_per_pixel) { + case 8: + bg_col = image->bg_color; + fg_col = image->fg_color; + break; + case 16: + bg_col = ((u32 *) (info->pseudo_palette))[image->bg_color]; + fg_col = ((u32 *) (info->pseudo_palette))[image->fg_color]; + break; + case 32: + bg_col = ((u32 *) (info->pseudo_palette))[image->bg_color]; + fg_col = ((u32 *) (info->pseudo_palette))[image->fg_color]; + break; + } + size = image->width * image->height; + + /* Source Base Address */ + writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE); + /* Destination Base Address */ + writel(((unsigned long) (info->screen_base) - + (unsigned long) viafb_FB_MM) >> 3, + viaparinfo->io_virt + VIA_REG_DSTBASE); + /* Pitch */ + pitch = (info->var.xres_virtual + 7) & ~7; + writel(VIA_PITCH_ENABLE | + (((pitch * + info->var.bits_per_pixel >> 3) >> 3) | (((pitch * + info->var. + bits_per_pixel + >> 3) >> 3) + << 16)), + viaparinfo->io_virt + VIA_REG_PITCH); + /* BitBlt Source Address */ + writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS); + /* BitBlt Destination Address */ + writel(((image->dy << 16) | image->dx), + viaparinfo->io_virt + VIA_REG_DSTPOS); + /* Dimension: width & height */ + writel((((image->height - 1) << 16) | (image->width - 1)), + viaparinfo->io_virt + VIA_REG_DIMENSION); + /* fb color */ + writel(fg_col, viaparinfo->io_virt + VIA_REG_FGCOLOR); + /* bg color */ + writel(bg_col, viaparinfo->io_virt + VIA_REG_BGCOLOR); + /* GE Command */ + writel(0xCC020142, viaparinfo->io_virt + VIA_REG_GECMD); + + for (i = 0; i < size / 4; i++) { + writel(*udata, viaparinfo->io_virt + VIA_MMIO_BLTBASE); + udata++; + } + +} + +static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + u8 data[CURSOR_SIZE / 8]; + u32 data_bak[CURSOR_SIZE / 32]; + u32 temp, xx, yy, bg_col = 0, fg_col = 0; + int size, i, j = 0; + static int hw_cursor; + struct viafb_par *p_viafb_par; + + if (viafb_accel) + hw_cursor = 1; + + if (!viafb_accel) { + if (hw_cursor) { + viafb_show_hw_cursor(info, HW_Cursor_OFF); + hw_cursor = 0; + } + return -ENODEV; + } + + if ((((struct viafb_par *)(info->par))->iga_path == IGA2) + && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) + return -ENODEV; + + /* When duoview and using lcd , use soft cursor */ + if (viafb_LCD_ON || ((struct viafb_par *)(info->par))->duoview) + return -ENODEV; + + viafb_show_hw_cursor(info, HW_Cursor_OFF); + viacursor = *cursor; + + if (cursor->set & FB_CUR_SETHOT) { + viacursor.hot = cursor->hot; + temp = ((viacursor.hot.x) << 16) + viacursor.hot.y; + writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_ORG); + } + + if (cursor->set & FB_CUR_SETPOS) { + viacursor.image.dx = cursor->image.dx; + viacursor.image.dy = cursor->image.dy; + yy = cursor->image.dy - info->var.yoffset; + xx = cursor->image.dx - info->var.xoffset; + temp = yy & 0xFFFF; + temp |= (xx << 16); + writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_POS); + } + + if (cursor->set & FB_CUR_SETSIZE) { + temp = readl(viaparinfo->io_virt + VIA_REG_CURSOR_MODE); + + if ((cursor->image.width <= 32) + && (cursor->image.height <= 32)) { + MAX_CURS = 32; + temp |= 0x2; + } else if ((cursor->image.width <= 64) + && (cursor->image.height <= 64)) { + MAX_CURS = 64; + temp &= 0xFFFFFFFD; + } else { + DEBUG_MSG(KERN_INFO + "The cursor image is biger than 64x64 bits...\n"); + return -ENXIO; + } + writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_MODE); + + viacursor.image.height = cursor->image.height; + viacursor.image.width = cursor->image.width; + } + + if (cursor->set & FB_CUR_SETCMAP) { + viacursor.image.fg_color = cursor->image.fg_color; + viacursor.image.bg_color = cursor->image.bg_color; + + switch (info->var.bits_per_pixel) { + case 8: + case 16: + case 32: + bg_col = + (0xFF << 24) | + (((info->cmap.red)[viacursor.image.bg_color] & + 0xFF00) << 8) | + ((info->cmap.green)[viacursor.image.bg_color] & + 0xFF00) | + (((info->cmap.blue)[viacursor.image.bg_color] & + 0xFF00) >> 8); + fg_col = + (0xFF << 24) | + (((info->cmap.red)[viacursor.image.fg_color] & + 0xFF00) << 8) | + ((info->cmap.green)[viacursor.image.fg_color] & + 0xFF00) | + (((info->cmap.blue)[viacursor.image.fg_color] & + 0xFF00) >> 8); + break; + default: + return 0; + } + + /* This is indeed a patch for VT3324/VT3353 */ + if (!info->par) + return 0; + p_viafb_par = (struct viafb_par *)info->par; + + if ((p_viafb_par->chip_info->gfx_chip_name == + UNICHROME_CX700) || + ((p_viafb_par->chip_info->gfx_chip_name == + UNICHROME_VX800))) { + bg_col = + (((info->cmap.red)[viacursor.image.bg_color] & + 0xFFC0) << 14) | + (((info->cmap.green)[viacursor.image.bg_color] & + 0xFFC0) << 4) | + (((info->cmap.blue)[viacursor.image.bg_color] & + 0xFFC0) >> 6); + fg_col = + (((info->cmap.red)[viacursor.image.fg_color] & + 0xFFC0) << 14) | + (((info->cmap.green)[viacursor.image.fg_color] & + 0xFFC0) << 4) | + (((info->cmap.blue)[viacursor.image.fg_color] & + 0xFFC0) >> 6); + } + + writel(bg_col, viaparinfo->io_virt + VIA_REG_CURSOR_BG); + writel(fg_col, viaparinfo->io_virt + VIA_REG_CURSOR_FG); + } + + if (cursor->set & FB_CUR_SETSHAPE) { + size = + ((viacursor.image.width + 7) >> 3) * + viacursor.image.height; + + if (MAX_CURS == 32) { + for (i = 0; i < (CURSOR_SIZE / 32); i++) { + data_bak[i] = 0x0; + data_bak[i + 1] = 0xFFFFFFFF; + i += 1; + } + } else if (MAX_CURS == 64) { + for (i = 0; i < (CURSOR_SIZE / 32); i++) { + data_bak[i] = 0x0; + data_bak[i + 1] = 0x0; + data_bak[i + 2] = 0xFFFFFFFF; + data_bak[i + 3] = 0xFFFFFFFF; + i += 3; + } + } + + switch (viacursor.rop) { + case ROP_XOR: + for (i = 0; i < size; i++) + data[i] = viacursor.mask[i]; + break; + case ROP_COPY: + + for (i = 0; i < size; i++) + data[i] = viacursor.mask[i]; + break; + default: + break; + } + + if (MAX_CURS == 32) { + for (i = 0; i < size; i++) { + data_bak[j] = (u32) data[i]; + data_bak[j + 1] = ~data_bak[j]; + j += 2; + } + } else if (MAX_CURS == 64) { + for (i = 0; i < size; i++) { + data_bak[j] = (u32) data[i]; + data_bak[j + 1] = 0x0; + data_bak[j + 2] = ~data_bak[j]; + data_bak[j + 3] = ~data_bak[j + 1]; + j += 4; + } + } + + memcpy(((struct viafb_par *)(info->par))->fbmem_virt + + ((struct viafb_par *)(info->par))->cursor_start, + data_bak, CURSOR_SIZE); + } + + if (viacursor.enable) + viafb_show_hw_cursor(info, HW_Cursor_ON); + + return 0; +} + +static int viafb_sync(struct fb_info *info) +{ + if (viafb_accel) + viafb_wait_engine_idle(); + return 0; +} + +int viafb_get_mode_index(int hres, int vres, int flag) +{ + u32 i; + DEBUG_MSG(KERN_INFO "viafb_get_mode_index!\n"); + + for (i = 0; viafb_modentry[i].mode_index != VIA_RES_INVALID; i++) + if (viafb_modentry[i].xres == hres && + viafb_modentry[i].yres == vres) + break; + + viafb_resMode = viafb_modentry[i].mode_index; + if (flag) + viafb_mode1 = viafb_modentry[i].mode_res; + else + viafb_mode = viafb_modentry[i].mode_res; + + return viafb_resMode; +} + +static void check_available_device_to_enable(int device_id) +{ + int device_num = 0; + + /* Initialize: */ + viafb_CRT_ON = STATE_OFF; + viafb_DVI_ON = STATE_OFF; + viafb_LCD_ON = STATE_OFF; + viafb_LCD2_ON = STATE_OFF; + viafb_DeviceStatus = None_Device; + + if ((device_id & CRT_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) { + viafb_CRT_ON = STATE_ON; + device_num++; + viafb_DeviceStatus |= CRT_Device; + } + + if ((device_id & DVI_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) { + viafb_DVI_ON = STATE_ON; + device_num++; + viafb_DeviceStatus |= DVI_Device; + } + + if ((device_id & LCD_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) { + viafb_LCD_ON = STATE_ON; + device_num++; + viafb_DeviceStatus |= LCD_Device; + } + + if ((device_id & LCD2_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) { + viafb_LCD2_ON = STATE_ON; + device_num++; + viafb_DeviceStatus |= LCD2_Device; + } + + if (viafb_DeviceStatus == None_Device) { + /* Use CRT as default active device: */ + viafb_CRT_ON = STATE_ON; + viafb_DeviceStatus = CRT_Device; + } + DEBUG_MSG(KERN_INFO "Device Status:%x", viafb_DeviceStatus); +} + +static void viafb_set_device(struct device_t active_dev) +{ + /* Check available device to enable: */ + int device_id = None_Device; + if (active_dev.crt) + device_id |= CRT_Device; + if (active_dev.dvi) + device_id |= DVI_Device; + if (active_dev.lcd) + device_id |= LCD_Device; + + check_available_device_to_enable(device_id); + + /* Check property of LCD: */ + if (viafb_LCD_ON) { + if (active_dev.lcd_dsp_cent) { + viaparinfo->lvds_setting_info->display_method = + viafb_lcd_dsp_method = LCD_CENTERING; + } else { + viaparinfo->lvds_setting_info->display_method = + viafb_lcd_dsp_method = LCD_EXPANDSION; + } + + if (active_dev.lcd_mode == LCD_SPWG) { + viaparinfo->lvds_setting_info->lcd_mode = + viafb_lcd_mode = LCD_SPWG; + } else { + viaparinfo->lvds_setting_info->lcd_mode = + viafb_lcd_mode = LCD_OPENLDI; + } + + if (active_dev.lcd_panel_id <= LCD_PANEL_ID_MAXIMUM) { + viafb_lcd_panel_id = active_dev.lcd_panel_id; + viafb_init_lcd_size(); + } + } + + /* Check property of mode: */ + if (!active_dev.xres1) + viafb_second_xres = 640; + else + viafb_second_xres = active_dev.xres1; + if (!active_dev.yres1) + viafb_second_yres = 480; + else + viafb_second_yres = active_dev.yres1; + if (active_dev.bpp != 0) + viafb_bpp = active_dev.bpp; + if (active_dev.bpp1 != 0) + viafb_bpp1 = active_dev.bpp1; + if (active_dev.refresh != 0) + viafb_refresh = active_dev.refresh; + if (active_dev.refresh1 != 0) + viafb_refresh1 = active_dev.refresh1; + if ((active_dev.samm == STATE_OFF) || (active_dev.samm == STATE_ON)) + viafb_SAMM_ON = active_dev.samm; + viafb_primary_dev = active_dev.primary_dev; + + viafb_set_start_addr(); + viafb_set_iga_path(); +} + +static void viafb_set_video_device(u32 video_dev_info) +{ + viaparinfo->video_on_crt = STATE_OFF; + viaparinfo->video_on_dvi = STATE_OFF; + viaparinfo->video_on_lcd = STATE_OFF; + + /* Check available device to enable: */ + if ((video_dev_info & CRT_Device) == CRT_Device) + viaparinfo->video_on_crt = STATE_ON; + else if ((video_dev_info & DVI_Device) == DVI_Device) + viaparinfo->video_on_dvi = STATE_ON; + else if ((video_dev_info & LCD_Device) == LCD_Device) + viaparinfo->video_on_lcd = STATE_ON; +} + +static void viafb_get_video_device(u32 *video_dev_info) +{ + *video_dev_info = None_Device; + if (viaparinfo->video_on_crt == STATE_ON) + *video_dev_info |= CRT_Device; + else if (viaparinfo->video_on_dvi == STATE_ON) + *video_dev_info |= DVI_Device; + else if (viaparinfo->video_on_lcd == STATE_ON) + *video_dev_info |= LCD_Device; +} + +static int get_primary_device(void) +{ + int primary_device = 0; + /* Rule: device on iga1 path are the primary device. */ + if (viafb_SAMM_ON) { + if (viafb_CRT_ON) { + if (viaparinfo->crt_setting_info->iga_path == IGA1) { + DEBUG_MSG(KERN_INFO "CRT IGA Path:%d\n", + viaparinfo-> + crt_setting_info->iga_path); + primary_device = CRT_Device; + } + } + if (viafb_DVI_ON) { + if (viaparinfo->tmds_setting_info->iga_path == IGA1) { + DEBUG_MSG(KERN_INFO "DVI IGA Path:%d\n", + viaparinfo-> + tmds_setting_info->iga_path); + primary_device = DVI_Device; + } + } + if (viafb_LCD_ON) { + if (viaparinfo->lvds_setting_info->iga_path == IGA1) { + DEBUG_MSG(KERN_INFO "LCD IGA Path:%d\n", + viaparinfo-> + lvds_setting_info->iga_path); + primary_device = LCD_Device; + } + } + if (viafb_LCD2_ON) { + if (viaparinfo->lvds_setting_info2->iga_path == IGA1) { + DEBUG_MSG(KERN_INFO "LCD2 IGA Path:%d\n", + viaparinfo-> + lvds_setting_info2->iga_path); + primary_device = LCD2_Device; + } + } + } + return primary_device; +} + +static u8 is_duoview(void) +{ + if (0 == viafb_SAMM_ON) { + if (viafb_LCD_ON + viafb_LCD2_ON + + viafb_DVI_ON + viafb_CRT_ON == 2) + return true; + return false; + } else { + return false; + } +} + +static void apply_second_mode_setting(struct fb_var_screeninfo + *sec_var) +{ + u32 htotal, vtotal, long_refresh; + + htotal = sec_var->xres + sec_var->left_margin + + sec_var->right_margin + sec_var->hsync_len; + vtotal = sec_var->yres + sec_var->upper_margin + + sec_var->lower_margin + sec_var->vsync_len; + if ((sec_var->xres_virtual * (sec_var->bits_per_pixel >> 3)) & 0x1F) { + /*Is 32 bytes alignment? */ + /*32 pixel alignment */ + sec_var->xres_virtual = (sec_var->xres_virtual + 31) & ~31; + } + + htotal = sec_var->xres + sec_var->left_margin + + sec_var->right_margin + sec_var->hsync_len; + vtotal = sec_var->yres + sec_var->upper_margin + + sec_var->lower_margin + sec_var->vsync_len; + long_refresh = 1000000000UL / sec_var->pixclock * 1000; + long_refresh /= (htotal * vtotal); + + viafb_second_xres = sec_var->xres; + viafb_second_yres = sec_var->yres; + viafb_second_virtual_xres = sec_var->xres_virtual; + viafb_second_virtual_yres = sec_var->yres_virtual; + viafb_bpp1 = sec_var->bits_per_pixel; + viafb_refresh1 = viafb_get_refresh(sec_var->xres, sec_var->yres, + long_refresh); +} + +static int apply_device_setting(struct viafb_ioctl_setting setting_info, + struct fb_info *info) +{ + int need_set_mode = 0; + DEBUG_MSG(KERN_INFO "apply_device_setting\n"); + + if (setting_info.device_flag) { + need_set_mode = 1; + check_available_device_to_enable(setting_info.device_status); + } + + /* Unlock LCD's operation according to LCD flag + and check if the setting value is valid. */ + /* If the value is valid, apply the new setting value to the device. */ + if (viafb_LCD_ON) { + if (setting_info.lcd_operation_flag & OP_LCD_CENTERING) { + need_set_mode = 1; + if (setting_info.lcd_attributes.display_center) { + /* Centering */ + viaparinfo->lvds_setting_info->display_method = + LCD_CENTERING; + viafb_lcd_dsp_method = LCD_CENTERING; + viaparinfo->lvds_setting_info2->display_method = + viafb_lcd_dsp_method = LCD_CENTERING; + } else { + /* expandsion */ + viaparinfo->lvds_setting_info->display_method = + LCD_EXPANDSION; + viafb_lcd_dsp_method = LCD_EXPANDSION; + viaparinfo->lvds_setting_info2->display_method = + LCD_EXPANDSION; + viafb_lcd_dsp_method = LCD_EXPANDSION; + } + } + + if (setting_info.lcd_operation_flag & OP_LCD_MODE) { + need_set_mode = 1; + if (setting_info.lcd_attributes.lcd_mode == + LCD_SPWG) { + viaparinfo->lvds_setting_info->lcd_mode = + viafb_lcd_mode = LCD_SPWG; + } else { + viaparinfo->lvds_setting_info->lcd_mode = + viafb_lcd_mode = LCD_OPENLDI; + } + viaparinfo->lvds_setting_info2->lcd_mode = + viaparinfo->lvds_setting_info->lcd_mode; + } + + if (setting_info.lcd_operation_flag & OP_LCD_PANEL_ID) { + need_set_mode = 1; + if (setting_info.lcd_attributes.panel_id <= + LCD_PANEL_ID_MAXIMUM) { + viafb_lcd_panel_id = + setting_info.lcd_attributes.panel_id; + viafb_init_lcd_size(); + } + } + } + + if (0 != (setting_info.samm_status & OP_SAMM)) { + setting_info.samm_status = + setting_info.samm_status & (~OP_SAMM); + if (setting_info.samm_status == 0 + || setting_info.samm_status == 1) { + viafb_SAMM_ON = setting_info.samm_status; + + if (viafb_SAMM_ON) + viafb_primary_dev = setting_info.primary_device; + + viafb_set_start_addr(); + viafb_set_iga_path(); + } + need_set_mode = 1; + } + + viaparinfo->duoview = is_duoview(); + + if (!need_set_mode) { + ; + } else { + viafb_set_iga_path(); + viafb_set_par(info); + } + return true; +} + +static void retrieve_device_setting(struct viafb_ioctl_setting + *setting_info) +{ + + /* get device status */ + if (viafb_CRT_ON == 1) + setting_info->device_status = CRT_Device; + if (viafb_DVI_ON == 1) + setting_info->device_status |= DVI_Device; + if (viafb_LCD_ON == 1) + setting_info->device_status |= LCD_Device; + if (viafb_LCD2_ON == 1) + setting_info->device_status |= LCD2_Device; + if ((viaparinfo->video_on_crt == 1) && (viafb_CRT_ON == 1)) { + setting_info->video_device_status = + viaparinfo->crt_setting_info->iga_path; + } else if ((viaparinfo->video_on_dvi == 1) && (viafb_DVI_ON == 1)) { + setting_info->video_device_status = + viaparinfo->tmds_setting_info->iga_path; + } else if ((viaparinfo->video_on_lcd == 1) && (viafb_LCD_ON == 1)) { + setting_info->video_device_status = + viaparinfo->lvds_setting_info->iga_path; + } else { + setting_info->video_device_status = 0; + } + + setting_info->samm_status = viafb_SAMM_ON; + setting_info->primary_device = get_primary_device(); + + setting_info->first_dev_bpp = viafb_bpp; + setting_info->second_dev_bpp = viafb_bpp1; + + setting_info->first_dev_refresh = viafb_refresh; + setting_info->second_dev_refresh = viafb_refresh1; + + setting_info->first_dev_hor_res = viafb_hotplug_Xres; + setting_info->first_dev_ver_res = viafb_hotplug_Yres; + setting_info->second_dev_hor_res = viafb_second_xres; + setting_info->second_dev_ver_res = viafb_second_yres; + + /* Get lcd attributes */ + setting_info->lcd_attributes.display_center = viafb_lcd_dsp_method; + setting_info->lcd_attributes.panel_id = viafb_lcd_panel_id; + setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode; +} + +static void parse_active_dev(void) +{ + viafb_CRT_ON = STATE_OFF; + viafb_DVI_ON = STATE_OFF; + viafb_LCD_ON = STATE_OFF; + viafb_LCD2_ON = STATE_OFF; + /* 1. Modify the active status of devices. */ + /* 2. Keep the order of devices, so we can set corresponding + IGA path to devices in SAMM case. */ + /* Note: The previous of active_dev is primary device, + and the following is secondary device. */ + if (!strncmp(viafb_active_dev, "CRT+DVI", 7)) { + /* CRT+DVI */ + viafb_CRT_ON = STATE_ON; + viafb_DVI_ON = STATE_ON; + viafb_primary_dev = CRT_Device; + } else if (!strncmp(viafb_active_dev, "DVI+CRT", 7)) { + /* DVI+CRT */ + viafb_CRT_ON = STATE_ON; + viafb_DVI_ON = STATE_ON; + viafb_primary_dev = DVI_Device; + } else if (!strncmp(viafb_active_dev, "CRT+LCD", 7)) { + /* CRT+LCD */ + viafb_CRT_ON = STATE_ON; + viafb_LCD_ON = STATE_ON; + viafb_primary_dev = CRT_Device; + } else if (!strncmp(viafb_active_dev, "LCD+CRT", 7)) { + /* LCD+CRT */ + viafb_CRT_ON = STATE_ON; + viafb_LCD_ON = STATE_ON; + viafb_primary_dev = LCD_Device; + } else if (!strncmp(viafb_active_dev, "DVI+LCD", 7)) { + /* DVI+LCD */ + viafb_DVI_ON = STATE_ON; + viafb_LCD_ON = STATE_ON; + viafb_primary_dev = DVI_Device; + } else if (!strncmp(viafb_active_dev, "LCD+DVI", 7)) { + /* LCD+DVI */ + viafb_DVI_ON = STATE_ON; + viafb_LCD_ON = STATE_ON; + viafb_primary_dev = LCD_Device; + } else if (!strncmp(viafb_active_dev, "LCD+LCD2", 8)) { + viafb_LCD_ON = STATE_ON; + viafb_LCD2_ON = STATE_ON; + viafb_primary_dev = LCD_Device; + } else if (!strncmp(viafb_active_dev, "LCD2+LCD", 8)) { + viafb_LCD_ON = STATE_ON; + viafb_LCD2_ON = STATE_ON; + viafb_primary_dev = LCD2_Device; + } else if (!strncmp(viafb_active_dev, "CRT", 3)) { + /* CRT only */ + viafb_CRT_ON = STATE_ON; + viafb_SAMM_ON = STATE_OFF; + } else if (!strncmp(viafb_active_dev, "DVI", 3)) { + /* DVI only */ + viafb_DVI_ON = STATE_ON; + viafb_SAMM_ON = STATE_OFF; + } else if (!strncmp(viafb_active_dev, "LCD", 3)) { + /* LCD only */ + viafb_LCD_ON = STATE_ON; + viafb_SAMM_ON = STATE_OFF; + } else { + viafb_CRT_ON = STATE_ON; + viafb_SAMM_ON = STATE_OFF; + } + viaparinfo->duoview = is_duoview(); +} + +static void parse_video_dev(void) +{ + viaparinfo->video_on_crt = STATE_OFF; + viaparinfo->video_on_dvi = STATE_OFF; + viaparinfo->video_on_lcd = STATE_OFF; + + if (!strncmp(viafb_video_dev, "CRT", 3)) { + /* Video on CRT */ + viaparinfo->video_on_crt = STATE_ON; + } else if (!strncmp(viafb_video_dev, "DVI", 3)) { + /* Video on DVI */ + viaparinfo->video_on_dvi = STATE_ON; + } else if (!strncmp(viafb_video_dev, "LCD", 3)) { + /* Video on LCD */ + viaparinfo->video_on_lcd = STATE_ON; + } +} + +static int parse_port(char *opt_str, int *output_interface) +{ + if (!strncmp(opt_str, "DVP0", 4)) + *output_interface = INTERFACE_DVP0; + else if (!strncmp(opt_str, "DVP1", 4)) + *output_interface = INTERFACE_DVP1; + else if (!strncmp(opt_str, "DFP_HIGHLOW", 11)) + *output_interface = INTERFACE_DFP; + else if (!strncmp(opt_str, "DFP_HIGH", 8)) + *output_interface = INTERFACE_DFP_HIGH; + else if (!strncmp(opt_str, "DFP_LOW", 7)) + *output_interface = INTERFACE_DFP_LOW; + else + *output_interface = INTERFACE_NONE; + return 0; +} + +static void parse_lcd_port(void) +{ + parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info. + output_interface); + /*Initialize to avoid unexpected behavior */ + viaparinfo->chip_info->lvds_chip_info2.output_interface = + INTERFACE_NONE; + + DEBUG_MSG(KERN_INFO "parse_lcd_port: viafb_lcd_port:%s,interface:%d\n", + viafb_lcd_port, viaparinfo->chip_info->lvds_chip_info. + output_interface); +} + +static void parse_dvi_port(void) +{ + parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info. + output_interface); + + DEBUG_MSG(KERN_INFO "parse_dvi_port: viafb_dvi_port:%s,interface:%d\n", + viafb_dvi_port, viaparinfo->chip_info->tmds_chip_info. + output_interface); +} + +/* + * The proc filesystem read/write function, a simple proc implement to + * get/set the value of DPA DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1, + * DVP1Driving, DFPHigh, DFPLow CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], + * CR9B, SR65, CR97, CR99 + */ +static int viafb_dvp0_proc_read(char *buf, char **start, off_t offset, +int count, int *eof, void *data) +{ + int len = 0; + u8 dvp0_data_dri = 0, dvp0_clk_dri = 0, dvp0 = 0; + dvp0_data_dri = + (viafb_read_reg(VIASR, SR2A) & BIT5) >> 4 | + (viafb_read_reg(VIASR, SR1B) & BIT1) >> 1; + dvp0_clk_dri = + (viafb_read_reg(VIASR, SR2A) & BIT4) >> 3 | + (viafb_read_reg(VIASR, SR1E) & BIT2) >> 2; + dvp0 = viafb_read_reg(VIACR, CR96) & 0x0f; + len += + sprintf(buf + len, "%x %x %x\n", dvp0, dvp0_data_dri, dvp0_clk_dri); + *eof = 1; /*Inform kernel end of data */ + return len; +} +static int viafb_dvp0_proc_write(struct file *file, + const char __user *buffer, unsigned long count, void *data) +{ + char buf[20], *value, *pbuf; + u8 reg_val = 0; + unsigned long length, i; + if (count < 1) + return -EINVAL; + length = count > 20 ? 20 : count; + if (copy_from_user(&buf[0], buffer, length)) + return -EFAULT; + buf[length - 1] = '\0'; /*Ensure end string */ + pbuf = &buf[0]; + for (i = 0; i < 3; i++) { + value = strsep(&pbuf, " "); + if (value != NULL) { + strict_strtoul(value, 0, (unsigned long *)®_val); + DEBUG_MSG(KERN_INFO "DVP0:reg_val[%l]=:%x\n", i, + reg_val); + switch (i) { + case 0: + viafb_write_reg_mask(CR96, VIACR, + reg_val, 0x0f); + break; + case 1: + viafb_write_reg_mask(SR2A, VIASR, + reg_val << 4, BIT5); + viafb_write_reg_mask(SR1B, VIASR, + reg_val << 1, BIT1); + break; + case 2: + viafb_write_reg_mask(SR2A, VIASR, + reg_val << 3, BIT4); + viafb_write_reg_mask(SR1E, VIASR, + reg_val << 2, BIT2); + break; + default: + break; + } + } else { + break; + } + } + return count; +} +static int viafb_dvp1_proc_read(char *buf, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len = 0; + u8 dvp1 = 0, dvp1_data_dri = 0, dvp1_clk_dri = 0; + dvp1 = viafb_read_reg(VIACR, CR9B) & 0x0f; + dvp1_data_dri = (viafb_read_reg(VIASR, SR65) & 0x0c) >> 2; + dvp1_clk_dri = viafb_read_reg(VIASR, SR65) & 0x03; + len += + sprintf(buf + len, "%x %x %x\n", dvp1, dvp1_data_dri, dvp1_clk_dri); + *eof = 1; /*Inform kernel end of data */ + return len; +} +static int viafb_dvp1_proc_write(struct file *file, + const char __user *buffer, unsigned long count, void *data) +{ + char buf[20], *value, *pbuf; + u8 reg_val = 0; + unsigned long length, i; + if (count < 1) + return -EINVAL; + length = count > 20 ? 20 : count; + if (copy_from_user(&buf[0], buffer, length)) + return -EFAULT; + buf[length - 1] = '\0'; /*Ensure end string */ + pbuf = &buf[0]; + for (i = 0; i < 3; i++) { + value = strsep(&pbuf, " "); + if (value != NULL) { + strict_strtoul(value, 0, (unsigned long *)®_val); + switch (i) { + case 0: + viafb_write_reg_mask(CR9B, VIACR, + reg_val, 0x0f); + break; + case 1: + viafb_write_reg_mask(SR65, VIASR, + reg_val << 2, 0x0c); + break; + case 2: + viafb_write_reg_mask(SR65, VIASR, + reg_val, 0x03); + break; + default: + break; + } + } else { + break; + } + } + return count; +} + +static int viafb_dfph_proc_read(char *buf, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len = 0; + u8 dfp_high = 0; + dfp_high = viafb_read_reg(VIACR, CR97) & 0x0f; + len += sprintf(buf + len, "%x\n", dfp_high); + *eof = 1; /*Inform kernel end of data */ + return len; +} +static int viafb_dfph_proc_write(struct file *file, + const char __user *buffer, unsigned long count, void *data) +{ + char buf[20]; + u8 reg_val = 0; + unsigned long length; + if (count < 1) + return -EINVAL; + length = count > 20 ? 20 : count; + if (copy_from_user(&buf[0], buffer, length)) + return -EFAULT; + buf[length - 1] = '\0'; /*Ensure end string */ + strict_strtoul(&buf[0], 0, (unsigned long *)®_val); + viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f); + return count; +} +static int viafb_dfpl_proc_read(char *buf, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len = 0; + u8 dfp_low = 0; + dfp_low = viafb_read_reg(VIACR, CR99) & 0x0f; + len += sprintf(buf + len, "%x\n", dfp_low); + *eof = 1; /*Inform kernel end of data */ + return len; +} +static int viafb_dfpl_proc_write(struct file *file, + const char __user *buffer, unsigned long count, void *data) +{ + char buf[20]; + u8 reg_val = 0; + unsigned long length; + if (count < 1) + return -EINVAL; + length = count > 20 ? 20 : count; + if (copy_from_user(&buf[0], buffer, length)) + return -EFAULT; + buf[length - 1] = '\0'; /*Ensure end string */ + strict_strtoul(&buf[0], 0, (unsigned long *)®_val); + viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f); + return count; +} +static int viafb_vt1636_proc_read(char *buf, char **start, + off_t offset, int count, int *eof, void *data) +{ + int len = 0; + u8 vt1636_08 = 0, vt1636_09 = 0; + switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { + case VT1636_LVDS: + vt1636_08 = + viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info, 0x08) & 0x0f; + vt1636_09 = + viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info, 0x09) & 0x1f; + len += sprintf(buf + len, "%x %x\n", vt1636_08, vt1636_09); + break; + default: + break; + } + switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { + case VT1636_LVDS: + vt1636_08 = + viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2, + &viaparinfo->chip_info->lvds_chip_info2, 0x08) & 0x0f; + vt1636_09 = + viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2, + &viaparinfo->chip_info->lvds_chip_info2, 0x09) & 0x1f; + len += sprintf(buf + len, " %x %x\n", vt1636_08, vt1636_09); + break; + default: + break; + } + *eof = 1; /*Inform kernel end of data */ + return len; +} +static int viafb_vt1636_proc_write(struct file *file, + const char __user *buffer, unsigned long count, void *data) +{ + char buf[30], *value, *pbuf; + struct IODATA reg_val; + unsigned long length, i; + if (count < 1) + return -EINVAL; + length = count > 30 ? 30 : count; + if (copy_from_user(&buf[0], buffer, length)) + return -EFAULT; + buf[length - 1] = '\0'; /*Ensure end string */ + pbuf = &buf[0]; + switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) { + case VT1636_LVDS: + for (i = 0; i < 2; i++) { + value = strsep(&pbuf, " "); + if (value != NULL) { + strict_strtoul(value, 0, + (unsigned long *)®_val.Data); + switch (i) { + case 0: + reg_val.Index = 0x08; + reg_val.Mask = 0x0f; + viafb_gpio_i2c_write_mask_lvds + (viaparinfo->lvds_setting_info, + &viaparinfo-> + chip_info->lvds_chip_info, + reg_val); + break; + case 1: + reg_val.Index = 0x09; + reg_val.Mask = 0x1f; + viafb_gpio_i2c_write_mask_lvds + (viaparinfo->lvds_setting_info, + &viaparinfo-> + chip_info->lvds_chip_info, + reg_val); + break; + default: + break; + } + } else { + break; + } + } + break; + default: + break; + } + switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { + case VT1636_LVDS: + for (i = 0; i < 2; i++) { + value = strsep(&pbuf, " "); + if (value != NULL) { + strict_strtoul(value, 0, + (unsigned long *)®_val.Data); + switch (i) { + case 0: + reg_val.Index = 0x08; + reg_val.Mask = 0x0f; + viafb_gpio_i2c_write_mask_lvds + (viaparinfo->lvds_setting_info2, + &viaparinfo-> + chip_info->lvds_chip_info2, + reg_val); + break; + case 1: + reg_val.Index = 0x09; + reg_val.Mask = 0x1f; + viafb_gpio_i2c_write_mask_lvds + (viaparinfo->lvds_setting_info2, + &viaparinfo-> + chip_info->lvds_chip_info2, + reg_val); + break; + default: + break; + } + } else { + break; + } + } + break; + default: + break; + } + return count; +} + +static void viafb_init_proc(struct proc_dir_entry *viafb_entry) +{ + struct proc_dir_entry *entry; + viafb_entry = proc_mkdir("viafb", NULL); + if (viafb_entry) { + entry = create_proc_entry("dvp0", 0, viafb_entry); + if (entry) { + entry->owner = THIS_MODULE; + entry->read_proc = viafb_dvp0_proc_read; + entry->write_proc = viafb_dvp0_proc_write; + } + entry = create_proc_entry("dvp1", 0, viafb_entry); + if (entry) { + entry->owner = THIS_MODULE; + entry->read_proc = viafb_dvp1_proc_read; + entry->write_proc = viafb_dvp1_proc_write; + } + entry = create_proc_entry("dfph", 0, viafb_entry); + if (entry) { + entry->owner = THIS_MODULE; + entry->read_proc = viafb_dfph_proc_read; + entry->write_proc = viafb_dfph_proc_write; + } + entry = create_proc_entry("dfpl", 0, viafb_entry); + if (entry) { + entry->owner = THIS_MODULE; + entry->read_proc = viafb_dfpl_proc_read; + entry->write_proc = viafb_dfpl_proc_write; + } + if (VT1636_LVDS == viaparinfo->chip_info->lvds_chip_info. + lvds_chip_name || VT1636_LVDS == + viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { + entry = create_proc_entry("vt1636", 0, viafb_entry); + if (entry) { + entry->owner = THIS_MODULE; + entry->read_proc = viafb_vt1636_proc_read; + entry->write_proc = viafb_vt1636_proc_write; + } + } + + } +} +static void viafb_remove_proc(struct proc_dir_entry *viafb_entry) +{ + /* no problem if it was not registered */ + remove_proc_entry("dvp0", viafb_entry);/* parent dir */ + remove_proc_entry("dvp1", viafb_entry); + remove_proc_entry("dfph", viafb_entry); + remove_proc_entry("dfpl", viafb_entry); + remove_proc_entry("vt1636", viafb_entry); + remove_proc_entry("vt1625", viafb_entry); +} + +static int __devinit via_pci_probe(void) +{ + unsigned int default_xres, default_yres; + char *tmpc, *tmpm; + char *tmpc_sec, *tmpm_sec; + int vmode_index; + u32 tmds_length, lvds_length, crt_length, chip_length, viafb_par_length; + + DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n"); + + viafb_par_length = ALIGN(sizeof(struct viafb_par), BITS_PER_LONG/8); + tmds_length = ALIGN(sizeof(struct tmds_setting_information), + BITS_PER_LONG/8); + lvds_length = ALIGN(sizeof(struct lvds_setting_information), + BITS_PER_LONG/8); + crt_length = ALIGN(sizeof(struct lvds_setting_information), + BITS_PER_LONG/8); + chip_length = ALIGN(sizeof(struct chip_information), BITS_PER_LONG/8); + + /* Allocate fb_info and ***_par here, also including some other needed + * variables + */ + viafbinfo = framebuffer_alloc(viafb_par_length + 2 * lvds_length + + tmds_length + crt_length + chip_length, NULL); + if (!viafbinfo) { + printk(KERN_ERR"Could not allocate memory for viafb_info.\n"); + return -ENODEV; + } + + viaparinfo = (struct viafb_par *)viafbinfo->par; + viaparinfo->tmds_setting_info = (struct tmds_setting_information *) + ((unsigned long)viaparinfo + viafb_par_length); + viaparinfo->lvds_setting_info = (struct lvds_setting_information *) + ((unsigned long)viaparinfo->tmds_setting_info + tmds_length); + viaparinfo->lvds_setting_info2 = (struct lvds_setting_information *) + ((unsigned long)viaparinfo->lvds_setting_info + lvds_length); + viaparinfo->crt_setting_info = (struct crt_setting_information *) + ((unsigned long)viaparinfo->lvds_setting_info2 + lvds_length); + viaparinfo->chip_info = (struct chip_information *) + ((unsigned long)viaparinfo->crt_setting_info + crt_length); + + if (viafb_dual_fb) + viafb_SAMM_ON = 1; + parse_active_dev(); + parse_video_dev(); + parse_lcd_port(); + parse_dvi_port(); + + /* for dual-fb must viafb_SAMM_ON=1 and viafb_dual_fb=1 */ + if (!viafb_SAMM_ON) + viafb_dual_fb = 0; + + /* Set up I2C bus stuff */ + viafb_create_i2c_bus(viaparinfo); + + viafb_init_chip_info(); + viafb_get_fb_info(&viaparinfo->fbmem, &viaparinfo->memsize); + viaparinfo->fbmem_free = viaparinfo->memsize; + viaparinfo->fbmem_used = 0; + viaparinfo->fbmem_virt = ioremap_nocache(viaparinfo->fbmem, + viaparinfo->memsize); + viafbinfo->screen_base = (char *)viaparinfo->fbmem_virt; + + if (!viaparinfo->fbmem_virt) { + printk(KERN_INFO "ioremap failed\n"); + return -1; + } + + viafb_get_mmio_info(&viaparinfo->mmio_base, &viaparinfo->mmio_len); + viaparinfo->io_virt = ioremap_nocache(viaparinfo->mmio_base, + viaparinfo->mmio_len); + + viafbinfo->node = 0; + viafbinfo->fbops = &viafb_ops; + viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + + viafbinfo->pseudo_palette = pseudo_pal; + if (viafb_accel) { + viafb_init_accel(); + viafb_init_2d_engine(); + viafb_hw_cursor_init(); + } + + if (viafb_second_size && (viafb_second_size < 8)) { + viafb_second_offset = viaparinfo->fbmem_free - + viafb_second_size * 1024 * 1024; + } else { + viafb_second_size = 8; + viafb_second_offset = viaparinfo->fbmem_free - + viafb_second_size * 1024 * 1024; + } + + viafb_FB_MM = viaparinfo->fbmem_virt; + tmpm = viafb_mode; + tmpc = strsep(&tmpm, "x"); + strict_strtoul(tmpc, 0, (unsigned long *)&default_xres); + strict_strtoul(tmpm, 0, (unsigned long *)&default_yres); + + vmode_index = viafb_get_mode_index(default_xres, default_yres, 0); + DEBUG_MSG(KERN_INFO "0->index=%d\n", vmode_index); + + if (viafb_SAMM_ON == 1) { + if (strcmp(viafb_mode, viafb_mode1)) { + tmpm_sec = viafb_mode1; + tmpc_sec = strsep(&tmpm_sec, "x"); + strict_strtoul(tmpc_sec, 0, + (unsigned long *)&viafb_second_xres); + strict_strtoul(tmpm_sec, 0, + (unsigned long *)&viafb_second_yres); + } else { + viafb_second_xres = default_xres; + viafb_second_yres = default_yres; + } + if (0 == viafb_second_virtual_xres) { + switch (viafb_second_xres) { + case 1400: + viafb_second_virtual_xres = 1408; + break; + default: + viafb_second_virtual_xres = viafb_second_xres; + break; + } + } + if (0 == viafb_second_virtual_yres) + viafb_second_virtual_yres = viafb_second_yres; + } + + switch (viafb_bpp) { + case 0 ... 8: + viafb_bpp = 8; + break; + case 9 ... 16: + viafb_bpp = 16; + break; + case 17 ... 32: + viafb_bpp = 32; + break; + default: + viafb_bpp = 8; + } + default_var.xres = default_xres; + default_var.yres = default_yres; + switch (default_xres) { + case 1400: + default_var.xres_virtual = 1408; + break; + default: + default_var.xres_virtual = default_xres; + break; + } + default_var.yres_virtual = default_yres; + default_var.bits_per_pixel = viafb_bpp; + if (default_var.bits_per_pixel == 15) + default_var.bits_per_pixel = 16; + default_var.pixclock = + viafb_get_pixclock(default_xres, default_yres, viafb_refresh); + default_var.left_margin = (default_xres >> 3) & 0xf8; + default_var.right_margin = 32; + default_var.upper_margin = 16; + default_var.lower_margin = 4; + default_var.hsync_len = default_var.left_margin; + default_var.vsync_len = 4; + default_var.accel_flags = 0; + + if (viafb_accel) { + viafbinfo->flags |= + (FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT); + default_var.accel_flags |= FB_ACCELF_TEXT; + } else + viafbinfo->flags |= FBINFO_HWACCEL_DISABLED; + + if (viafb_dual_fb) { + viafbinfo1 = framebuffer_alloc(viafb_par_length, NULL); + if (!viafbinfo1) { + printk(KERN_ERR + "allocate the second framebuffer struct error\n"); + framebuffer_release(viafbinfo); + return -ENOMEM; + } + viaparinfo1 = viafbinfo1->par; + memcpy(viaparinfo1, viaparinfo, viafb_par_length); + viaparinfo1->memsize = viaparinfo->memsize - + viafb_second_offset; + viaparinfo->memsize = viafb_second_offset; + viaparinfo1->fbmem_virt = viaparinfo->fbmem_virt + + viafb_second_offset; + viaparinfo1->fbmem = viaparinfo->fbmem + viafb_second_offset; + + viaparinfo1->fbmem_used = viaparinfo->fbmem_used; + viaparinfo1->fbmem_free = viaparinfo1->memsize - + viaparinfo1->fbmem_used; + viaparinfo->fbmem_free = viaparinfo->memsize; + viaparinfo->fbmem_used = 0; + if (viafb_accel) { + viaparinfo1->cursor_start = + viaparinfo->cursor_start - viafb_second_offset; + viaparinfo1->VQ_start = viaparinfo->VQ_start - + viafb_second_offset; + viaparinfo1->VQ_end = viaparinfo->VQ_end - + viafb_second_offset; + } + + memcpy(viafbinfo1, viafbinfo, sizeof(struct fb_info)); + viafbinfo1->screen_base = viafbinfo->screen_base + + viafb_second_offset; + viafbinfo1->fix.smem_start = viaparinfo1->fbmem; + viafbinfo1->fix.smem_len = viaparinfo1->fbmem_free; + + default_var.xres = viafb_second_xres; + default_var.yres = viafb_second_yres; + default_var.xres_virtual = viafb_second_virtual_xres; + default_var.yres_virtual = viafb_second_virtual_yres; + if (viafb_bpp1 != viafb_bpp) + viafb_bpp1 = viafb_bpp; + default_var.bits_per_pixel = viafb_bpp1; + default_var.pixclock = + viafb_get_pixclock(viafb_second_xres, viafb_second_yres, + viafb_refresh); + default_var.left_margin = (viafb_second_xres >> 3) & 0xf8; + default_var.right_margin = 32; + default_var.upper_margin = 16; + default_var.lower_margin = 4; + default_var.hsync_len = default_var.left_margin; + default_var.vsync_len = 4; + + viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1); + viafb_check_var(&default_var, viafbinfo1); + viafbinfo1->var = default_var; + viafb_update_viafb_par(viafbinfo); + viafb_update_fix(&viafbinfo1->fix, viafbinfo1); + } + + viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo); + viafb_check_var(&default_var, viafbinfo); + viafbinfo->var = default_var; + viafb_update_viafb_par(viafbinfo); + viafb_update_fix(&viafbinfo->fix, viafbinfo); + default_var.activate = FB_ACTIVATE_NOW; + fb_alloc_cmap(&viafbinfo->cmap, 256, 0); + + if (viafb_dual_fb && (viafb_primary_dev == LCD_Device) + && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) { + if (register_framebuffer(viafbinfo1) < 0) + return -EINVAL; + } + if (register_framebuffer(viafbinfo) < 0) + return -EINVAL; + + if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device) + || (viaparinfo->chip_info->gfx_chip_name != + UNICHROME_CLE266))) { + if (register_framebuffer(viafbinfo1) < 0) + return -EINVAL; + } + DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n", + viafbinfo->node, viafbinfo->fix.id, default_var.xres, + default_var.yres, default_var.bits_per_pixel); + + viafb_init_proc(viaparinfo->proc_entry); + viafb_init_dac(IGA2); + return 0; +} + +static void __devexit via_pci_remove(void) +{ + DEBUG_MSG(KERN_INFO "via_pci_remove!\n"); + fb_dealloc_cmap(&viafbinfo->cmap); + unregister_framebuffer(viafbinfo); + if (viafb_dual_fb) + unregister_framebuffer(viafbinfo1); + iounmap((void *)viaparinfo->fbmem_virt); + iounmap(viaparinfo->io_virt); + + viafb_delete_i2c_buss(viaparinfo); + + framebuffer_release(viafbinfo); + if (viafb_dual_fb) + framebuffer_release(viafbinfo1); + + viafb_remove_proc(viaparinfo->proc_entry); +} + +#ifndef MODULE +static int __init viafb_setup(char *options) +{ + char *this_opt; + DEBUG_MSG(KERN_INFO "viafb_setup!\n"); + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + + if (!strncmp(this_opt, "viafb_mode1=", 12)) + viafb_mode1 = kstrdup(this_opt + 12, GFP_KERNEL); + else if (!strncmp(this_opt, "viafb_mode=", 11)) + viafb_mode = kstrdup(this_opt + 11, GFP_KERNEL); + else if (!strncmp(this_opt, "viafb_bpp1=", 11)) + strict_strtoul(this_opt + 11, 0, + (unsigned long *)&viafb_bpp1); + else if (!strncmp(this_opt, "viafb_bpp=", 10)) + strict_strtoul(this_opt + 10, 0, + (unsigned long *)&viafb_bpp); + else if (!strncmp(this_opt, "viafb_refresh1=", 15)) + strict_strtoul(this_opt + 15, 0, + (unsigned long *)&viafb_refresh1); + else if (!strncmp(this_opt, "viafb_refresh=", 14)) + strict_strtoul(this_opt + 14, 0, + (unsigned long *)&viafb_refresh); + else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21)) + strict_strtoul(this_opt + 21, 0, + (unsigned long *)&viafb_lcd_dsp_method); + else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19)) + strict_strtoul(this_opt + 19, 0, + (unsigned long *)&viafb_lcd_panel_id); + else if (!strncmp(this_opt, "viafb_accel=", 12)) + strict_strtoul(this_opt + 12, 0, + (unsigned long *)&viafb_accel); + else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14)) + strict_strtoul(this_opt + 14, 0, + (unsigned long *)&viafb_SAMM_ON); + else if (!strncmp(this_opt, "viafb_active_dev=", 17)) + viafb_active_dev = kstrdup(this_opt + 17, GFP_KERNEL); + else if (!strncmp(this_opt, + "viafb_display_hardware_layout=", 30)) + strict_strtoul(this_opt + 30, 0, + (unsigned long *)&viafb_display_hardware_layout); + else if (!strncmp(this_opt, "viafb_second_size=", 18)) + strict_strtoul(this_opt + 18, 0, + (unsigned long *)&viafb_second_size); + else if (!strncmp(this_opt, + "viafb_platform_epia_dvi=", 24)) + strict_strtoul(this_opt + 24, 0, + (unsigned long *)&viafb_platform_epia_dvi); + else if (!strncmp(this_opt, + "viafb_device_lcd_dualedge=", 26)) + strict_strtoul(this_opt + 26, 0, + (unsigned long *)&viafb_device_lcd_dualedge); + else if (!strncmp(this_opt, "viafb_bus_width=", 16)) + strict_strtoul(this_opt + 16, 0, + (unsigned long *)&viafb_bus_width); + else if (!strncmp(this_opt, "viafb_lcd_mode=", 15)) + strict_strtoul(this_opt + 15, 0, + (unsigned long *)&viafb_lcd_mode); + else if (!strncmp(this_opt, "viafb_video_dev=", 16)) + viafb_video_dev = kstrdup(this_opt + 16, GFP_KERNEL); + else if (!strncmp(this_opt, "viafb_lcd_port=", 15)) + viafb_lcd_port = kstrdup(this_opt + 15, GFP_KERNEL); + else if (!strncmp(this_opt, "viafb_dvi_port=", 15)) + viafb_dvi_port = kstrdup(this_opt + 15, GFP_KERNEL); + } + return 0; +} +#endif + +static int __init viafb_init(void) +{ +#ifndef MODULE + char *option = NULL; + if (fb_get_options("viafb", &option)) + return -ENODEV; + viafb_setup(option); +#endif + printk(KERN_INFO + "VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n", + VERSION_MAJOR, VERSION_MINOR); + return via_pci_probe(); +} + +static void __exit viafb_exit(void) +{ + DEBUG_MSG(KERN_INFO "viafb_exit!\n"); + via_pci_remove(); +} + +static struct fb_ops viafb_ops = { + .owner = THIS_MODULE, + .fb_open = viafb_open, + .fb_release = viafb_release, + .fb_check_var = viafb_check_var, + .fb_set_par = viafb_set_par, + .fb_setcolreg = viafb_setcolreg, + .fb_pan_display = viafb_pan_display, + .fb_blank = viafb_blank, + .fb_fillrect = viafb_fillrect, + .fb_copyarea = viafb_copyarea, + .fb_imageblit = viafb_imageblit, + .fb_cursor = viafb_cursor, + .fb_ioctl = viafb_ioctl, + .fb_sync = viafb_sync, + .fb_setcmap = viafb_setcmap, +}; + +module_init(viafb_init); +module_exit(viafb_exit); + +#ifdef MODULE +module_param(viafb_memsize, int, 0); + +module_param(viafb_mode, charp, 0); +MODULE_PARM_DESC(viafb_mode, "Set resolution (default=640x480)"); + +module_param(viafb_mode1, charp, 0); +MODULE_PARM_DESC(viafb_mode1, "Set resolution (default=640x480)"); + +module_param(viafb_bpp, int, 0); +MODULE_PARM_DESC(viafb_bpp, "Set color depth (default=32bpp)"); + +module_param(viafb_bpp1, int, 0); +MODULE_PARM_DESC(viafb_bpp1, "Set color depth (default=32bpp)"); + +module_param(viafb_refresh, int, 0); +MODULE_PARM_DESC(viafb_refresh, + "Set CRT viafb_refresh rate (default = 60)"); + +module_param(viafb_refresh1, int, 0); +MODULE_PARM_DESC(viafb_refresh1, + "Set CRT refresh rate (default = 60)"); + +module_param(viafb_lcd_panel_id, int, 0); +MODULE_PARM_DESC(viafb_lcd_panel_id, + "Set Flat Panel type(Default=1024x768)"); + +module_param(viafb_lcd_dsp_method, int, 0); +MODULE_PARM_DESC(viafb_lcd_dsp_method, + "Set Flat Panel display scaling method.(Default=Expandsion)"); + +module_param(viafb_SAMM_ON, int, 0); +MODULE_PARM_DESC(viafb_SAMM_ON, + "Turn on/off flag of SAMM(Default=OFF)"); + +module_param(viafb_accel, int, 0); +MODULE_PARM_DESC(viafb_accel, + "Set 2D Hardware Acceleration.(Default = OFF)"); + +module_param(viafb_active_dev, charp, 0); +MODULE_PARM_DESC(viafb_active_dev, "Specify active devices."); + +module_param(viafb_display_hardware_layout, int, 0); +MODULE_PARM_DESC(viafb_display_hardware_layout, + "Display Hardware Layout (LCD Only, DVI Only...,etc)"); + +module_param(viafb_second_size, int, 0); +MODULE_PARM_DESC(viafb_second_size, + "Set secondary device memory size"); + +module_param(viafb_dual_fb, int, 0); +MODULE_PARM_DESC(viafb_dual_fb, + "Turn on/off flag of dual framebuffer devices.(Default = OFF)"); + +module_param(viafb_platform_epia_dvi, int, 0); +MODULE_PARM_DESC(viafb_platform_epia_dvi, + "Turn on/off flag of DVI devices on EPIA board.(Default = OFF)"); + +module_param(viafb_device_lcd_dualedge, int, 0); +MODULE_PARM_DESC(viafb_device_lcd_dualedge, + "Turn on/off flag of dual edge panel.(Default = OFF)"); + +module_param(viafb_bus_width, int, 0); +MODULE_PARM_DESC(viafb_bus_width, + "Set bus width of panel.(Default = 12)"); + +module_param(viafb_lcd_mode, int, 0); +MODULE_PARM_DESC(viafb_lcd_mode, + "Set Flat Panel mode(Default=OPENLDI)"); + +module_param(viafb_video_dev, charp, 0); +MODULE_PARM_DESC(viafb_video_dev, "Specify video devices."); + +module_param(viafb_lcd_port, charp, 0); +MODULE_PARM_DESC(viafb_lcd_port, "Specify LCD output port."); + +module_param(viafb_dvi_port, charp, 0); +MODULE_PARM_DESC(viafb_dvi_port, "Specify DVI output port."); + +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h new file mode 100644 index 00000000000..a4158e87287 --- /dev/null +++ b/drivers/video/via/viafbdev.h @@ -0,0 +1,112 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VIAFBDEV_H__ +#define __VIAFBDEV_H__ + +#include <linux/proc_fs.h> +#include <linux/fb.h> + +#include "ioctl.h" +#include "share.h" +#include "chip.h" +#include "hw.h" +#include "via_i2c.h" + +#define VERSION_MAJOR 2 +#define VERSION_KERNEL 6 /* For kernel 2.6 */ + +#define VERSION_OS 0 /* 0: for 32 bits OS, 1: for 64 bits OS */ +#define VERSION_MINOR 4 + +struct viafb_par { + int bpp; + int hres; + int vres; + int linelength; + u32 xoffset; + u32 yoffset; + + void __iomem *fbmem_virt; /*framebuffer virtual memory address */ + void __iomem *io_virt; /*iospace virtual memory address */ + unsigned int fbmem; /*framebuffer physical memory address */ + unsigned int memsize; /*size of fbmem */ + unsigned int io; /*io space address */ + unsigned long mmio_base; /*mmio base address */ + unsigned long mmio_len; /*mmio base length */ + u32 fbmem_free; /* Free FB memory */ + u32 fbmem_used; /* Use FB memory size */ + u32 cursor_start; /* Cursor Start Address */ + u32 VQ_start; /* Virtual Queue Start Address */ + u32 VQ_end; /* Virtual Queue End Address */ + u32 iga_path; + struct proc_dir_entry *proc_entry; /*viafb proc entry */ + u8 duoview; /*Is working in duoview mode? */ + + /* I2C stuff */ + struct via_i2c_stuff i2c_stuff; + + /* All the information will be needed to set engine */ + struct tmds_setting_information *tmds_setting_info; + struct crt_setting_information *crt_setting_info; + struct lvds_setting_information *lvds_setting_info; + struct lvds_setting_information *lvds_setting_info2; + struct chip_information *chip_info; + + /* some information related to video playing */ + int video_on_crt; + int video_on_dvi; + int video_on_lcd; + +}; +struct viafb_modeinfo { + u32 xres; + u32 yres; + int mode_index; + char *mode_res; +}; +extern unsigned int viafb_second_virtual_yres; +extern unsigned int viafb_second_virtual_xres; +extern unsigned int viafb_second_offset; +extern int viafb_second_size; +extern int viafb_SAMM_ON; +extern int viafb_dual_fb; +extern int viafb_LCD2_ON; +extern int viafb_LCD_ON; +extern int viafb_DVI_ON; +extern int viafb_accel; +extern int viafb_hotplug; +extern int viafb_memsize; + +extern int strict_strtoul(const char *cp, unsigned int base, + unsigned long *res); + +void viafb_memory_pitch_patch(struct fb_info *info); +void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh, + int mode_index); +int viafb_get_mode_index(int hres, int vres, int flag); +u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information + *plvds_chip_info, u8 index); +void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information + *plvds_chip_info, struct IODATA io_data); +#endif /* __VIAFBDEV_H__ */ diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c new file mode 100644 index 00000000000..6dcf583a837 --- /dev/null +++ b/drivers/video/via/viamode.c @@ -0,0 +1,1086 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" +struct res_map_refresh res_map_refresh_tbl[] = { +/*hres, vres, vclock, vmode_refresh*/ + {480, 640, RES_480X640_60HZ_PIXCLOCK, 60}, + {640, 480, RES_640X480_60HZ_PIXCLOCK, 60}, + {640, 480, RES_640X480_75HZ_PIXCLOCK, 75}, + {640, 480, RES_640X480_85HZ_PIXCLOCK, 85}, + {640, 480, RES_640X480_100HZ_PIXCLOCK, 100}, + {640, 480, RES_640X480_120HZ_PIXCLOCK, 120}, + {720, 480, RES_720X480_60HZ_PIXCLOCK, 60}, + {720, 576, RES_720X576_60HZ_PIXCLOCK, 60}, + {800, 480, RES_800X480_60HZ_PIXCLOCK, 60}, + {800, 600, RES_800X600_60HZ_PIXCLOCK, 60}, + {800, 600, RES_800X600_75HZ_PIXCLOCK, 75}, + {800, 600, RES_800X600_85HZ_PIXCLOCK, 85}, + {800, 600, RES_800X600_100HZ_PIXCLOCK, 100}, + {800, 600, RES_800X600_120HZ_PIXCLOCK, 120}, + {848, 480, RES_848X480_60HZ_PIXCLOCK, 60}, + {856, 480, RES_856X480_60HZ_PIXCLOCK, 60}, + {1024, 512, RES_1024X512_60HZ_PIXCLOCK, 60}, + {1024, 600, RES_1024X600_60HZ_PIXCLOCK, 60}, + {1024, 768, RES_1024X768_60HZ_PIXCLOCK, 60}, + {1024, 768, RES_1024X768_75HZ_PIXCLOCK, 75}, + {1024, 768, RES_1024X768_85HZ_PIXCLOCK, 85}, + {1024, 768, RES_1024X768_100HZ_PIXCLOCK, 100}, +/* {1152,864, RES_1152X864_70HZ_PIXCLOCK, 70},*/ + {1152, 864, RES_1152X864_75HZ_PIXCLOCK, 75}, + {1280, 768, RES_1280X768_60HZ_PIXCLOCK, 60}, + {1280, 800, RES_1280X800_60HZ_PIXCLOCK, 60}, + {1280, 960, RES_1280X960_60HZ_PIXCLOCK, 60}, + {1280, 1024, RES_1280X1024_60HZ_PIXCLOCK, 60}, + {1280, 1024, RES_1280X1024_75HZ_PIXCLOCK, 75}, + {1280, 1024, RES_1280X768_85HZ_PIXCLOCK, 85}, + {1440, 1050, RES_1440X1050_60HZ_PIXCLOCK, 60}, + {1600, 1200, RES_1600X1200_60HZ_PIXCLOCK, 60}, + {1600, 1200, RES_1600X1200_75HZ_PIXCLOCK, 75}, + {1280, 720, RES_1280X720_60HZ_PIXCLOCK, 60}, + {1920, 1080, RES_1920X1080_60HZ_PIXCLOCK, 60}, + {1400, 1050, RES_1400X1050_60HZ_PIXCLOCK, 60}, + {1400, 1050, RES_1400X1050_75HZ_PIXCLOCK, 75}, + {1368, 768, RES_1368X768_60HZ_PIXCLOCK, 60}, + {960, 600, RES_960X600_60HZ_PIXCLOCK, 60}, + {1000, 600, RES_1000X600_60HZ_PIXCLOCK, 60}, + {1024, 576, RES_1024X576_60HZ_PIXCLOCK, 60}, + {1088, 612, RES_1088X612_60HZ_PIXCLOCK, 60}, + {1152, 720, RES_1152X720_60HZ_PIXCLOCK, 60}, + {1200, 720, RES_1200X720_60HZ_PIXCLOCK, 60}, + {1280, 600, RES_1280X600_60HZ_PIXCLOCK, 60}, + {1280, 720, RES_1280X720_50HZ_PIXCLOCK, 50}, + {1280, 768, RES_1280X768_50HZ_PIXCLOCK, 50}, + {1360, 768, RES_1360X768_60HZ_PIXCLOCK, 60}, + {1366, 768, RES_1366X768_50HZ_PIXCLOCK, 50}, + {1366, 768, RES_1366X768_60HZ_PIXCLOCK, 60}, + {1440, 900, RES_1440X900_60HZ_PIXCLOCK, 60}, + {1440, 900, RES_1440X900_75HZ_PIXCLOCK, 75}, + {1600, 900, RES_1600X900_60HZ_PIXCLOCK, 60}, + {1600, 1024, RES_1600X1024_60HZ_PIXCLOCK, 60}, + {1680, 1050, RES_1680X1050_60HZ_PIXCLOCK, 60}, + {1680, 1050, RES_1680X1050_75HZ_PIXCLOCK, 75}, + {1792, 1344, RES_1792X1344_60HZ_PIXCLOCK, 60}, + {1856, 1392, RES_1856X1392_60HZ_PIXCLOCK, 60}, + {1920, 1200, RES_1920X1200_60HZ_PIXCLOCK, 60}, + {1920, 1440, RES_1920X1440_60HZ_PIXCLOCK, 60}, + {1920, 1440, RES_1920X1440_75HZ_PIXCLOCK, 75}, + {2048, 1536, RES_2048X1536_60HZ_PIXCLOCK, 60} +}; + +struct io_reg CN400_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, +{VIASR, SR15, 0x02, 0x02}, +{VIASR, SR16, 0xBF, 0x08}, +{VIASR, SR17, 0xFF, 0x1F}, +{VIASR, SR18, 0xFF, 0x4E}, +{VIASR, SR1A, 0xFB, 0x08}, +{VIASR, SR1E, 0x0F, 0x01}, +{VIASR, SR2A, 0xFF, 0x00}, +{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ +{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ +{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ +{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */ +{VIACR, CR32, 0xFF, 0x00}, +{VIACR, CR33, 0xFF, 0x00}, +{VIACR, CR34, 0xFF, 0x00}, +{VIACR, CR35, 0xFF, 0x00}, +{VIACR, CR36, 0x08, 0x00}, +{VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR69, 0xFF, 0x00}, +{VIACR, CR6A, 0xFF, 0x40}, +{VIACR, CR6B, 0xFF, 0x00}, +{VIACR, CR6C, 0xFF, 0x00}, +{VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */ +{VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */ +{VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */ +{VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */ +{VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */ +{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */ +{VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */ +{VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */ +{VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */ +{VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */ +{VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */ +{VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */ +{VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */ +{VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ +{VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ +{VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ +{VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ +{VIACR, CR8B, 0xFF, 0x69}, /* LCD Power Sequence Control 0 */ +{VIACR, CR8C, 0xFF, 0x57}, /* LCD Power Sequence Control 1 */ +{VIACR, CR8D, 0xFF, 0x00}, /* LCD Power Sequence Control 2 */ +{VIACR, CR8E, 0xFF, 0x7B}, /* LCD Power Sequence Control 3 */ +{VIACR, CR8F, 0xFF, 0x03}, /* LCD Power Sequence Control 4 */ +{VIACR, CR90, 0xFF, 0x30}, /* LCD Power Sequence Control 5 */ +{VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */ +{VIACR, CR96, 0xFF, 0x00}, +{VIACR, CR97, 0xFF, 0x00}, +{VIACR, CR99, 0xFF, 0x00}, +{VIACR, CR9B, 0xFF, 0x00} +}; + +/* Video Mode Table for VT3314 chipset*/ +/* Common Setting for Video Mode */ +struct io_reg CN700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, +{VIASR, SR15, 0x02, 0x02}, +{VIASR, SR16, 0xBF, 0x08}, +{VIASR, SR17, 0xFF, 0x1F}, +{VIASR, SR18, 0xFF, 0x4E}, +{VIASR, SR1A, 0xFB, 0x82}, +{VIASR, SR1B, 0xFF, 0xF0}, +{VIASR, SR1F, 0xFF, 0x00}, +{VIASR, SR1E, 0xFF, 0x01}, +{VIASR, SR22, 0xFF, 0x1F}, +{VIASR, SR2A, 0x0F, 0x00}, +{VIASR, SR2E, 0xFF, 0xFF}, +{VIASR, SR3F, 0xFF, 0xFF}, +{VIASR, SR40, 0xF7, 0x00}, +{VIASR, CR30, 0xFF, 0x04}, +{VIACR, CR32, 0xFF, 0x00}, +{VIACR, CR33, 0x7F, 0x00}, +{VIACR, CR34, 0xFF, 0x00}, +{VIACR, CR35, 0xFF, 0x00}, +{VIACR, CR36, 0xFF, 0x31}, +{VIACR, CR41, 0xFF, 0x80}, +{VIACR, CR42, 0xFF, 0x00}, +{VIACR, CR55, 0x80, 0x00}, +{VIACR, CR5D, 0x80, 0x00}, /*Horizontal Retrace Start bit[11] should be 0*/ +{VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR68, 0xFF, 0x67}, /* Default FIFO For IGA2 */ +{VIACR, CR69, 0xFF, 0x00}, +{VIACR, CR6A, 0xFD, 0x40}, +{VIACR, CR6B, 0xFF, 0x00}, +{VIACR, CR6C, 0xFF, 0x00}, +{VIACR, CR77, 0xFF, 0x00}, /* LCD scaling Factor */ +{VIACR, CR78, 0xFF, 0x00}, /* LCD scaling Factor */ +{VIACR, CR79, 0xFF, 0x00}, /* LCD scaling Factor */ +{VIACR, CR9F, 0x03, 0x00}, /* LCD scaling Factor */ +{VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */ +{VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */ +{VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */ +{VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */ +{VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */ +{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */ +{VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */ +{VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */ +{VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */ +{VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */ +{VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */ +{VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */ +{VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */ +{VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ +{VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ +{VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ +{VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ +{VIACR, CR8B, 0xFF, 0x5D}, /* LCD Power Sequence Control 0 */ +{VIACR, CR8C, 0xFF, 0x2B}, /* LCD Power Sequence Control 1 */ +{VIACR, CR8D, 0xFF, 0x6F}, /* LCD Power Sequence Control 2 */ +{VIACR, CR8E, 0xFF, 0x2B}, /* LCD Power Sequence Control 3 */ +{VIACR, CR8F, 0xFF, 0x01}, /* LCD Power Sequence Control 4 */ +{VIACR, CR90, 0xFF, 0x01}, /* LCD Power Sequence Control 5 */ +{VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */ +{VIACR, CR96, 0xFF, 0x00}, +{VIACR, CR97, 0xFF, 0x00}, +{VIACR, CR99, 0xFF, 0x00}, +{VIACR, CR9B, 0xFF, 0x00}, +{VIACR, CR9D, 0xFF, 0x80}, +{VIACR, CR9E, 0xFF, 0x80} +}; + +struct io_reg KM400_ModeXregs[] = { + {VIASR, SR10, 0xFF, 0x01}, /* Unlock Register */ + {VIASR, SR16, 0xFF, 0x08}, /* Display FIFO threshold Control */ + {VIASR, SR17, 0xFF, 0x1F}, /* Display FIFO Control */ + {VIASR, SR18, 0xFF, 0x4E}, /* GFX PREQ threshold */ + {VIASR, SR1A, 0xFF, 0x0a}, /* GFX PREQ threshold */ + {VIASR, SR1F, 0xFF, 0x00}, /* Memory Control 0 */ + {VIASR, SR1B, 0xFF, 0xF0}, /* Power Management Control 0 */ + {VIASR, SR1E, 0xFF, 0x01}, /* Power Management Control */ + {VIASR, SR20, 0xFF, 0x00}, /* Sequencer Arbiter Control 0 */ + {VIASR, SR21, 0xFF, 0x00}, /* Sequencer Arbiter Control 1 */ + {VIASR, SR22, 0xFF, 0x1F}, /* Display Arbiter Control 1 */ + {VIASR, SR2A, 0xFF, 0x00}, /* Power Management Control 5 */ + {VIASR, SR2D, 0xFF, 0xFF}, /* Power Management Control 1 */ + {VIASR, SR2E, 0xFF, 0xFF}, /* Power Management Control 2 */ + {VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ + {VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ + {VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ + {VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */ + {VIACR, CR33, 0xFF, 0x00}, + {VIACR, CR55, 0x80, 0x00}, + {VIACR, CR5D, 0x80, 0x00}, + {VIACR, CR36, 0xFF, 0x01}, /* Power Mangement 3 */ + {VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */ + {VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */ + {VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */ + {VIACR, CR68, 0xFF, 0x67}, /* Default FIFO For IGA2 */ + {VIACR, CR6A, 0x20, 0x20}, /* Extended FIFO On */ + {VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */ + {VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */ + {VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */ + {VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */ + {VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */ + {VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */ + {VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */ + {VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */ + {VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */ + {VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */ + {VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */ + {VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */ + {VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */ + {VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ + {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ + {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ + {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ + {VIACR, CR8B, 0xFF, 0x2D}, /* LCD Power Sequence Control 0 */ + {VIACR, CR8C, 0xFF, 0x2D}, /* LCD Power Sequence Control 1 */ + {VIACR, CR8D, 0xFF, 0xC8}, /* LCD Power Sequence Control 2 */ + {VIACR, CR8E, 0xFF, 0x36}, /* LCD Power Sequence Control 3 */ + {VIACR, CR8F, 0xFF, 0x00}, /* LCD Power Sequence Control 4 */ + {VIACR, CR90, 0xFF, 0x10}, /* LCD Power Sequence Control 5 */ + {VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */ + {VIACR, CR96, 0xFF, 0x03}, /* DVP0 ; DVP0 Clock Skew */ + {VIACR, CR97, 0xFF, 0x03}, /* DFP high ; DFPH Clock Skew */ + {VIACR, CR99, 0xFF, 0x03}, /* DFP low ; DFPL Clock Skew*/ + {VIACR, CR9B, 0xFF, 0x07} /* DVI on DVP1 ; DVP1 Clock Skew*/ +}; + +/* For VT3324: Common Setting for Video Mode */ +struct io_reg CX700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, +{VIASR, SR15, 0x02, 0x02}, +{VIASR, SR16, 0xBF, 0x08}, +{VIASR, SR17, 0xFF, 0x1F}, +{VIASR, SR18, 0xFF, 0x4E}, +{VIASR, SR1A, 0xFB, 0x08}, +{VIASR, SR1B, 0xFF, 0xF0}, +{VIASR, SR1E, 0xFF, 0x01}, +{VIASR, SR2A, 0xFF, 0x00}, +{VIASR, SR2D, 0xFF, 0xFF}, /* VCK and LCK PLL power on. */ +{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ +{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ +{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ +{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */ +{VIACR, CR32, 0xFF, 0x00}, +{VIACR, CR33, 0xFF, 0x00}, +{VIACR, CR34, 0xFF, 0x00}, +{VIACR, CR35, 0xFF, 0x00}, +{VIACR, CR36, 0x08, 0x00}, +{VIACR, CR47, 0xC8, 0x00}, /* Clear VCK Plus. */ +{VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CRA3, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR69, 0xFF, 0x00}, +{VIACR, CR6A, 0xFF, 0x40}, +{VIACR, CR6B, 0xFF, 0x00}, +{VIACR, CR6C, 0xFF, 0x00}, +{VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */ +{VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */ +{VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */ +{VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */ +{VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */ +{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */ +{VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */ +{VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */ +{VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */ +{VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */ +{VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */ +{VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */ +{VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */ +{VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ +{VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ +{VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ +{VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ +{VIACR, CRD4, 0xFF, 0x81}, /* Second power sequence control */ +{VIACR, CR8B, 0xFF, 0x5D}, /* LCD Power Sequence Control 0 */ +{VIACR, CR8C, 0xFF, 0x2B}, /* LCD Power Sequence Control 1 */ +{VIACR, CR8D, 0xFF, 0x6F}, /* LCD Power Sequence Control 2 */ +{VIACR, CR8E, 0xFF, 0x2B}, /* LCD Power Sequence Control 3 */ +{VIACR, CR8F, 0xFF, 0x01}, /* LCD Power Sequence Control 4 */ +{VIACR, CR90, 0xFF, 0x01}, /* LCD Power Sequence Control 5 */ +{VIACR, CR91, 0xFF, 0x80}, /* 24/12 bit LVDS Data off */ +{VIACR, CR96, 0xFF, 0x00}, +{VIACR, CR97, 0xFF, 0x00}, +{VIACR, CR99, 0xFF, 0x00}, +{VIACR, CR9B, 0xFF, 0x00}, +{VIACR, CRD2, 0xFF, 0xFF} /* TMDS/LVDS control register. */ +}; + +/* For VT3353: Common Setting for Video Mode */ +struct io_reg VX800_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01}, +{VIASR, SR15, 0x02, 0x02}, +{VIASR, SR16, 0xBF, 0x08}, +{VIASR, SR17, 0xFF, 0x1F}, +{VIASR, SR18, 0xFF, 0x4E}, +{VIASR, SR1A, 0xFB, 0x08}, +{VIASR, SR1B, 0xFF, 0xF0}, +{VIASR, SR1E, 0xFF, 0x01}, +{VIASR, SR2A, 0xFF, 0x00}, +{VIASR, SR2D, 0xFF, 0xFF}, /* VCK and LCK PLL power on. */ +{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */ +{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */ +{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */ +{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */ +{VIACR, CR32, 0xFF, 0x00}, +{VIACR, CR33, 0xFF, 0x00}, +{VIACR, CR34, 0xFF, 0x00}, +{VIACR, CR35, 0xFF, 0x00}, +{VIACR, CR36, 0x08, 0x00}, +{VIACR, CR47, 0xC8, 0x00}, /* Clear VCK Plus. */ +{VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CRA3, 0xFF, 0x00}, /* Secondary Display Starting Address */ +{VIACR, CR69, 0xFF, 0x00}, +{VIACR, CR6A, 0xFF, 0x40}, +{VIACR, CR6B, 0xFF, 0x00}, +{VIACR, CR6C, 0xFF, 0x00}, +{VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */ +{VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */ +{VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */ +{VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */ +{VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */ +{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */ +{VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */ +{VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */ +{VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */ +{VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */ +{VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */ +{VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */ +{VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */ +{VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ +{VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */ +{VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */ +{VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */ +{VIACR, CRD4, 0xFF, 0x81}, /* Second power sequence control */ +{VIACR, CR8B, 0xFF, 0x5D}, /* LCD Power Sequence Control 0 */ +{VIACR, CR8C, 0xFF, 0x2B}, /* LCD Power Sequence Control 1 */ +{VIACR, CR8D, 0xFF, 0x6F}, /* LCD Power Sequence Control 2 */ +{VIACR, CR8E, 0xFF, 0x2B}, /* LCD Power Sequence Control 3 */ +{VIACR, CR8F, 0xFF, 0x01}, /* LCD Power Sequence Control 4 */ +{VIACR, CR90, 0xFF, 0x01}, /* LCD Power Sequence Control 5 */ +{VIACR, CR91, 0xFF, 0x80}, /* 24/12 bit LVDS Data off */ +{VIACR, CR96, 0xFF, 0x00}, +{VIACR, CR97, 0xFF, 0x00}, +{VIACR, CR99, 0xFF, 0x00}, +{VIACR, CR9B, 0xFF, 0x00}, +{VIACR, CRD2, 0xFF, 0xFF} /* TMDS/LVDS control register. */ +}; + +/* Video Mode Table */ +/* Common Setting for Video Mode */ +struct io_reg CLE266_ModeXregs[] = { {VIASR, SR1E, 0xF0, 0x00}, +{VIASR, SR2A, 0x0F, 0x00}, +{VIASR, SR15, 0x02, 0x02}, +{VIASR, SR16, 0xBF, 0x08}, +{VIASR, SR17, 0xFF, 0x1F}, +{VIASR, SR18, 0xFF, 0x4E}, +{VIASR, SR1A, 0xFB, 0x08}, + +{VIACR, CR32, 0xFF, 0x00}, +{VIACR, CR34, 0xFF, 0x00}, +{VIACR, CR35, 0xFF, 0x00}, +{VIACR, CR36, 0x08, 0x00}, +{VIACR, CR6A, 0xFF, 0x80}, +{VIACR, CR6A, 0xFF, 0xC0}, + +{VIACR, CR55, 0x80, 0x00}, +{VIACR, CR5D, 0x80, 0x00}, + +{VIAGR, GR20, 0xFF, 0x00}, +{VIAGR, GR21, 0xFF, 0x00}, +{VIAGR, GR22, 0xFF, 0x00}, + /* LCD Parameters */ +{VIACR, CR7A, 0xFF, 0x01}, /* LCD Parameter 1 */ +{VIACR, CR7B, 0xFF, 0x02}, /* LCD Parameter 2 */ +{VIACR, CR7C, 0xFF, 0x03}, /* LCD Parameter 3 */ +{VIACR, CR7D, 0xFF, 0x04}, /* LCD Parameter 4 */ +{VIACR, CR7E, 0xFF, 0x07}, /* LCD Parameter 5 */ +{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Parameter 6 */ +{VIACR, CR80, 0xFF, 0x0D}, /* LCD Parameter 7 */ +{VIACR, CR81, 0xFF, 0x13}, /* LCD Parameter 8 */ +{VIACR, CR82, 0xFF, 0x16}, /* LCD Parameter 9 */ +{VIACR, CR83, 0xFF, 0x19}, /* LCD Parameter 10 */ +{VIACR, CR84, 0xFF, 0x1C}, /* LCD Parameter 11 */ +{VIACR, CR85, 0xFF, 0x1D}, /* LCD Parameter 12 */ +{VIACR, CR86, 0xFF, 0x1E}, /* LCD Parameter 13 */ +{VIACR, CR87, 0xFF, 0x1F}, /* LCD Parameter 14 */ + +}; + +/* Mode:1024X768 */ +struct io_reg PM1024x768[] = { {VIASR, 0x16, 0xBF, 0x0C}, +{VIASR, 0x18, 0xFF, 0x4C} +}; + +struct patch_table res_patch_table[] = { + {VIA_RES_1024X768, ARRAY_SIZE(PM1024x768), PM1024x768} +}; + +/* struct VPITTable { + unsigned char Misc; + unsigned char SR[StdSR]; + unsigned char CR[StdCR]; + unsigned char GR[StdGR]; + unsigned char AR[StdAR]; + };*/ + +struct VPITTable VPIT = { + /* Msic */ + 0xC7, + /* Sequencer */ + {0x01, 0x0F, 0x00, 0x0E}, + /* Graphic Controller */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF}, + /* Attribute Controller */ + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x01, 0x00, 0x0F, 0x00} +}; + +/********************/ +/* Mode Table */ +/********************/ + +/* 480x640 */ +struct crt_mode_table CRTM480x640[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_25_175M, M480X640_R60_HSP, M480X640_R60_VSP, + {624, 480, 480, 144, 504, 48, 663, 640, 640, 23, 641, 3} } /* GTF*/ +}; + +/* 640x480*/ +struct crt_mode_table CRTM640x480[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_25_175M, M640X480_R60_HSP, M640X480_R60_VSP, + {800, 640, 648, 144, 656, 96, 525, 480, 480, 45, 490, 2} }, + {REFRESH_75, CLK_31_500M, M640X480_R75_HSP, M640X480_R75_VSP, + {840, 640, 640, 200, 656, 64, 500, 480, 480, 20, 481, 3} }, + {REFRESH_85, CLK_36_000M, M640X480_R85_HSP, M640X480_R85_VSP, + {832, 640, 640, 192, 696, 56, 509, 480, 480, 29, 481, 3} }, + {REFRESH_100, CLK_43_163M, M640X480_R100_HSP, M640X480_R100_VSP, + {848, 640, 640, 208, 680, 64, 509, 480, 480, 29, 481, 3} }, /*GTF*/ + {REFRESH_120, CLK_52_406M, M640X480_R120_HSP, + M640X480_R120_VSP, + {848, 640, 640, 208, 680, 64, 515, 480, 480, 35, 481, + 3} } /*GTF*/ +}; + +/*720x480 (GTF)*/ +struct crt_mode_table CRTM720x480[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_26_880M, M720X480_R60_HSP, M720X480_R60_VSP, + {896, 720, 720, 176, 736, 72, 497, 480, 480, 17, 481, 3} } + +}; + +/*720x576 (GTF)*/ +struct crt_mode_table CRTM720x576[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_32_668M, M720X576_R60_HSP, M720X576_R60_VSP, + {912, 720, 720, 192, 744, 72, 597, 576, 576, 21, 577, 3} } +}; + +/* 800x480 (CVT) */ +struct crt_mode_table CRTM800x480[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_29_581M, M800X480_R60_HSP, M800X480_R60_VSP, + {992, 800, 800, 192, 824, 72, 500, 480, 480, 20, 483, 7} } +}; + +/* 800x600*/ +struct crt_mode_table CRTM800x600[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_40_000M, M800X600_R60_HSP, M800X600_R60_VSP, + {1056, 800, 800, 256, 840, 128, 628, 600, 600, 28, 601, 4} }, + {REFRESH_75, CLK_49_500M, M800X600_R75_HSP, M800X600_R75_VSP, + {1056, 800, 800, 256, 816, 80, 625, 600, 600, 25, 601, 3} }, + {REFRESH_85, CLK_56_250M, M800X600_R85_HSP, M800X600_R85_VSP, + {1048, 800, 800, 248, 832, 64, 631, 600, 600, 31, 601, 3} }, + {REFRESH_100, CLK_68_179M, M800X600_R100_HSP, M800X600_R100_VSP, + {1072, 800, 800, 272, 848, 88, 636, 600, 600, 36, 601, 3} }, + {REFRESH_120, CLK_83_950M, M800X600_R120_HSP, + M800X600_R120_VSP, + {1088, 800, 800, 288, 856, 88, 643, 600, 600, 43, 601, + 3} } +}; + +/* 848x480 (CVT) */ +struct crt_mode_table CRTM848x480[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_31_500M, M848X480_R60_HSP, M848X480_R60_VSP, + {1056, 848, 848, 208, 872, 80, 500, 480, 480, 20, 483, 5} } +}; + +/*856x480 (GTF) convert to 852x480*/ +struct crt_mode_table CRTM852x480[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_31_728M, M852X480_R60_HSP, M852X480_R60_VSP, + {1064, 856, 856, 208, 872, 88, 497, 480, 480, 17, 481, 3} } +}; + +/*1024x512 (GTF)*/ +struct crt_mode_table CRTM1024x512[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_41_291M, M1024X512_R60_HSP, M1024X512_R60_VSP, + {1296, 1024, 1024, 272, 1056, 104, 531, 512, 512, 19, 513, 3} } + +}; + +/* 1024x600*/ +struct crt_mode_table CRTM1024x600[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_48_875M, M1024X600_R60_HSP, M1024X600_R60_VSP, + {1312, 1024, 1024, 288, 1064, 104, 622, 600, 600, 22, 601, 3} }, +}; + +/* 1024x768*/ +struct crt_mode_table CRTM1024x768[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_65_000M, M1024X768_R60_HSP, M1024X768_R60_VSP, + {1344, 1024, 1024, 320, 1048, 136, 806, 768, 768, 38, 771, 6} }, + {REFRESH_75, CLK_78_750M, M1024X768_R75_HSP, M1024X768_R75_VSP, + {1312, 1024, 1024, 288, 1040, 96, 800, 768, 768, 32, 769, 3} }, + {REFRESH_85, CLK_94_500M, M1024X768_R85_HSP, M1024X768_R85_VSP, + {1376, 1024, 1024, 352, 1072, 96, 808, 768, 768, 40, 769, 3} }, + {REFRESH_100, CLK_113_309M, M1024X768_R100_HSP, M1024X768_R100_VSP, + {1392, 1024, 1024, 368, 1096, 112, 814, 768, 768, 46, 769, 3} } +}; + +/* 1152x864*/ +struct crt_mode_table CRTM1152x864[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_75, CLK_108_000M, M1152X864_R75_HSP, M1152X864_R75_VSP, + {1600, 1152, 1152, 448, 1216, 128, 900, 864, 864, 36, 865, 3} } + +}; + +/* 1280x720 (HDMI 720P)*/ +struct crt_mode_table CRTM1280x720[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_74_481M, M1280X720_R60_HSP, M1280X720_R60_VSP, + {1648, 1280, 1280, 368, 1392, 40, 750, 720, 720, 30, 725, 5} }, + {REFRESH_50, CLK_60_466M, M1280X720_R50_HSP, M1280X720_R50_VSP, + {1632, 1280, 1280, 352, 1328, 128, 741, 720, 720, 21, 721, 3} } +}; + +/*1280x768 (GTF)*/ +struct crt_mode_table CRTM1280x768[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_80_136M, M1280X768_R60_HSP, M1280X768_R60_VSP, + {1680, 1280, 1280, 400, 1344, 136, 795, 768, 768, 27, 769, 3} }, + {REFRESH_50, CLK_65_178M, M1280X768_R50_HSP, M1280X768_R50_VSP, + {1648, 1280, 1280, 368, 1336, 128, 791, 768, 768, 23, 769, 3} } +}; + +/* 1280x800 (CVT) */ +struct crt_mode_table CRTM1280x800[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_83_375M, M1280X800_R60_HSP, M1280X800_R60_VSP, + {1680, 1280, 1280, 400, 1352, 128, 831, 800, 800, 31, 803, 6} } +}; + +/*1280x960*/ +struct crt_mode_table CRTM1280x960[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_108_000M, M1280X960_R60_HSP, M1280X960_R60_VSP, + {1800, 1280, 1280, 520, 1376, 112, 1000, 960, 960, 40, 961, 3} } +}; + +/* 1280x1024*/ +struct crt_mode_table CRTM1280x1024[] = { + /*r_rate,vclk,,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_108_000M, M1280X1024_R60_HSP, M1280X1024_R60_VSP, + {1688, 1280, 1280, 408, 1328, 112, 1066, 1024, 1024, 42, 1025, + 3} }, + {REFRESH_75, CLK_135_000M, M1280X1024_R75_HSP, M1280X1024_R75_VSP, + {1688, 1280, 1280, 408, 1296, 144, 1066, 1024, 1024, 42, 1025, + 3} }, + {REFRESH_85, CLK_157_500M, M1280X1024_R85_HSP, M1280X1024_R85_VSP, + {1728, 1280, 1280, 448, 1344, 160, 1072, 1024, 1024, 48, 1025, 3} } +}; + +/* 1368x768 (GTF) */ +struct crt_mode_table CRTM1368x768[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_85_860M, M1368X768_R60_HSP, M1368X768_R60_VSP, + {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} } +}; + +/*1440x1050 (GTF)*/ +struct crt_mode_table CRTM1440x1050[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_125_104M, M1440X1050_R60_HSP, M1440X1050_R60_VSP, + {1936, 1440, 1440, 496, 1536, 152, 1077, 1040, 1040, 37, 1041, 3} } +}; + +/* 1600x1200*/ +struct crt_mode_table CRTM1600x1200[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_162_000M, M1600X1200_R60_HSP, M1600X1200_R60_VSP, + {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201, + 3} }, + {REFRESH_75, CLK_202_500M, M1600X1200_R75_HSP, M1600X1200_R75_VSP, + {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201, 3} } + +}; + +/* 1680x1050 (CVT) */ +struct crt_mode_table CRTM1680x1050[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_146_760M, M1680x1050_R60_HSP, M1680x1050_R60_VSP, + {2240, 1680, 1680, 560, 1784, 176, 1089, 1050, 1050, 39, 1053, + 6} }, + {REFRESH_75, CLK_187_000M, M1680x1050_R75_HSP, M1680x1050_R75_VSP, + {2272, 1680, 1680, 592, 1800, 176, 1099, 1050, 1050, 49, 1053, 6} } +}; + +/* 1680x1050 (CVT Reduce Blanking) */ +struct crt_mode_table CRTM1680x1050_RB[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_119_000M, M1680x1050_RB_R60_HSP, + M1680x1050_RB_R60_VSP, + {1840, 1680, 1680, 160, 1728, 32, 1080, 1050, 1050, 30, 1053, 6} } +}; + +/* 1920x1080 (CVT)*/ +struct crt_mode_table CRTM1920x1080[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_172_798M, M1920X1080_R60_HSP, M1920X1080_R60_VSP, + {2576, 1920, 1920, 656, 2048, 200, 1120, 1080, 1080, 40, 1083, 5} } +}; + +/* 1920x1080 (CVT with Reduce Blanking) */ +struct crt_mode_table CRTM1920x1080_RB[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_138_400M, M1920X1080_RB_R60_HSP, + M1920X1080_RB_R60_VSP, + {2080, 1920, 1920, 160, 1968, 32, 1111, 1080, 1080, 31, 1083, 5} } +}; + +/* 1920x1440*/ +struct crt_mode_table CRTM1920x1440[] = { + /*r_rate,vclk,hsp,vsp */ + /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_234_000M, M1920X1440_R60_HSP, M1920X1440_R60_VSP, + {2600, 1920, 1920, 680, 2048, 208, 1500, 1440, 1440, 60, 1441, + 3} }, + {REFRESH_75, CLK_297_500M, M1920X1440_R75_HSP, M1920X1440_R75_VSP, + {2640, 1920, 1920, 720, 2064, 224, 1500, 1440, 1440, 60, 1441, 3} } +}; + +/* 1400x1050 (CVT) */ +struct crt_mode_table CRTM1400x1050[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_121_750M, M1400X1050_R60_HSP, M1400X1050_R60_VSP, + {1864, 1400, 1400, 464, 1488, 144, 1089, 1050, 1050, 39, 1053, + 4} }, + {REFRESH_75, CLK_156_000M, M1400X1050_R75_HSP, M1400X1050_R75_VSP, + {1896, 1400, 1400, 496, 1504, 144, 1099, 1050, 1050, 49, 1053, 4} } +}; + +/* 1400x1050 (CVT Reduce Blanking) */ +struct crt_mode_table CRTM1400x1050_RB[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_101_000M, M1400X1050_RB_R60_HSP, + M1400X1050_RB_R60_VSP, + {1560, 1400, 1400, 160, 1448, 32, 1080, 1050, 1050, 30, 1053, 4} } +}; + +/* 960x600 (CVT) */ +struct crt_mode_table CRTM960x600[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_45_250M, M960X600_R60_HSP, M960X600_R60_VSP, + {1216, 960, 960, 256, 992, 96, 624, 600, 600, 24, 603, 6} } +}; + +/* 1000x600 (GTF) */ +struct crt_mode_table CRTM1000x600[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_48_000M, M1000X600_R60_HSP, M1000X600_R60_VSP, + {1288, 1000, 1000, 288, 1040, 104, 622, 600, 600, 22, 601, 3} } +}; + +/* 1024x576 (GTF) */ +struct crt_mode_table CRTM1024x576[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_46_996M, M1024X576_R60_HSP, M1024X576_R60_VSP, + {1312, 1024, 1024, 288, 1064, 104, 597, 576, 576, 21, 577, 3} } +}; + +/* 1088x612 (CVT) */ +struct crt_mode_table CRTM1088x612[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_52_977M, M1088X612_R60_HSP, M1088X612_R60_VSP, + {1392, 1088, 1088, 304, 1136, 104, 636, 612, 612, 24, 615, 5} } +}; + +/* 1152x720 (CVT) */ +struct crt_mode_table CRTM1152x720[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_66_750M, M1152X720_R60_HSP, M1152X720_R60_VSP, + {1488, 1152, 1152, 336, 1208, 112, 748, 720, 720, 28, 723, 6} } +}; + +/* 1200x720 (GTF) */ +struct crt_mode_table CRTM1200x720[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_70_159M, M1200X720_R60_HSP, M1200X720_R60_VSP, + {1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} } +}; + +/* 1280x600 (GTF) */ +struct crt_mode_table CRTM1280x600[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_61_500M, M1280x600_R60_HSP, M1280x600_R60_VSP, + {1648, 1280, 1280, 368, 1336, 128, 622, 600, 600, 22, 601, 3} } +}; + +/* 1360x768 (CVT) */ +struct crt_mode_table CRTM1360x768[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_84_750M, M1360X768_R60_HSP, M1360X768_R60_VSP, + {1776, 1360, 1360, 416, 1432, 136, 798, 768, 768, 30, 771, 5} } +}; + +/* 1360x768 (CVT Reduce Blanking) */ +struct crt_mode_table CRTM1360x768_RB[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_72_000M, M1360X768_RB_R60_HSP, + M1360X768_RB_R60_VSP, + {1520, 1360, 1360, 160, 1408, 32, 790, 768, 768, 22, 771, 5} } +}; + +/* 1366x768 (GTF) */ +struct crt_mode_table CRTM1366x768[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_85_860M, M1368X768_R60_HSP, M1368X768_R60_VSP, + {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} }, + {REFRESH_50, CLK_69_924M, M1368X768_R50_HSP, M1368X768_R50_VSP, + {1768, 1368, 1368, 400, 1424, 144, 791, 768, 768, 23, 769, 3} } +}; + +/* 1440x900 (CVT) */ +struct crt_mode_table CRTM1440x900[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_106_500M, M1440X900_R60_HSP, M1440X900_R60_VSP, + {1904, 1440, 1440, 464, 1520, 152, 934, 900, 900, 34, 903, 6} }, + {REFRESH_75, CLK_136_700M, M1440X900_R75_HSP, M1440X900_R75_VSP, + {1936, 1440, 1440, 496, 1536, 152, 942, 900, 900, 42, 903, 6} } +}; + +/* 1440x900 (CVT Reduce Blanking) */ +struct crt_mode_table CRTM1440x900_RB[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_88_750M, M1440X900_RB_R60_HSP, + M1440X900_RB_R60_VSP, + {1600, 1440, 1440, 160, 1488, 32, 926, 900, 900, 26, 903, 6} } +}; + +/* 1600x900 (CVT) */ +struct crt_mode_table CRTM1600x900[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_118_840M, M1600X900_R60_HSP, M1600X900_R60_VSP, + {2112, 1600, 1600, 512, 1688, 168, 934, 900, 900, 34, 903, 5} } +}; + +/* 1600x900 (CVT Reduce Blanking) */ +struct crt_mode_table CRTM1600x900_RB[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_97_750M, M1600X900_RB_R60_HSP, + M1600X900_RB_R60_VSP, + {1760, 1600, 1600, 160, 1648, 32, 926, 900, 900, 26, 903, 5} } +}; + +/* 1600x1024 (GTF) */ +struct crt_mode_table CRTM1600x1024[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_136_700M, M1600X1024_R60_HSP, M1600X1024_R60_VSP, + {2144, 1600, 1600, 544, 1704, 168, 1060, 1024, 1024, 36, 1025, 3} } +}; + +/* 1792x1344 (DMT) */ +struct crt_mode_table CRTM1792x1344[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_204_000M, M1792x1344_R60_HSP, M1792x1344_R60_VSP, + {2448, 1792, 1792, 656, 1920, 200, 1394, 1344, 1344, 50, 1345, 3} } +}; + +/* 1856x1392 (DMT) */ +struct crt_mode_table CRTM1856x1392[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_218_500M, M1856x1392_R60_HSP, M1856x1392_R60_VSP, + {2528, 1856, 1856, 672, 1952, 224, 1439, 1392, 1392, 47, 1393, 3} } +}; + +/* 1920x1200 (CVT) */ +struct crt_mode_table CRTM1920x1200[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_193_295M, M1920X1200_R60_HSP, M1920X1200_R60_VSP, + {2592, 1920, 1920, 672, 2056, 200, 1245, 1200, 1200, 45, 1203, 6} } +}; + +/* 1920x1200 (CVT with Reduce Blanking) */ +struct crt_mode_table CRTM1920x1200_RB[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_153_920M, M1920X1200_RB_R60_HSP, + M1920X1200_RB_R60_VSP, + {2080, 1920, 1920, 160, 1968, 32, 1235, 1200, 1200, 35, 1203, 6} } +}; + +/* 2048x1536 (CVT) */ +struct crt_mode_table CRTM2048x1536[] = { + /* r_rate, vclk, hsp, vsp */ + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {REFRESH_60, CLK_267_250M, M2048x1536_R60_HSP, M2048x1536_R60_VSP, + {2800, 2048, 2048, 752, 2200, 224, 1592, 1536, 1536, 56, 1539, 4} } +}; + +/* Video Mode Table */ +/* struct VideoModeTable {*/ +/* int ModeIndex;*/ +/* struct crt_mode_table *crtc;*/ +/* int mode_array;*/ +/* };*/ +struct VideoModeTable CLE266Modes[] = { + /* Display : 480x640 (GTF) */ + {VIA_RES_480X640, CRTM480x640, ARRAY_SIZE(CRTM480x640)}, + + /* Display : 640x480 */ + {VIA_RES_640X480, CRTM640x480, ARRAY_SIZE(CRTM640x480)}, + + /* Display : 720x480 (GTF) */ + {VIA_RES_720X480, CRTM720x480, ARRAY_SIZE(CRTM720x480)}, + + /* Display : 720x576 (GTF) */ + {VIA_RES_720X576, CRTM720x576, ARRAY_SIZE(CRTM720x576)}, + + /* Display : 800x600 */ + {VIA_RES_800X600, CRTM800x600, ARRAY_SIZE(CRTM800x600)}, + + /* Display : 800x480 (CVT) */ + {VIA_RES_800X480, CRTM800x480, ARRAY_SIZE(CRTM800x480)}, + + /* Display : 848x480 (CVT) */ + {VIA_RES_848X480, CRTM848x480, ARRAY_SIZE(CRTM848x480)}, + + /* Display : 852x480 (GTF) */ + {VIA_RES_856X480, CRTM852x480, ARRAY_SIZE(CRTM852x480)}, + + /* Display : 1024x512 (GTF) */ + {VIA_RES_1024X512, CRTM1024x512, ARRAY_SIZE(CRTM1024x512)}, + + /* Display : 1024x600 */ + {VIA_RES_1024X600, CRTM1024x600, ARRAY_SIZE(CRTM1024x600)}, + + /* Display : 1024x576 (GTF) */ + /*{ VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)}, */ + + /* Display : 1024x768 */ + {VIA_RES_1024X768, CRTM1024x768, ARRAY_SIZE(CRTM1024x768)}, + + /* Display : 1152x864 */ + {VIA_RES_1152X864, CRTM1152x864, ARRAY_SIZE(CRTM1152x864)}, + + /* Display : 1280x768 (GTF) */ + {VIA_RES_1280X768, CRTM1280x768, ARRAY_SIZE(CRTM1280x768)}, + + /* Display : 960x600 (CVT) */ + {VIA_RES_960X600, CRTM960x600, ARRAY_SIZE(CRTM960x600)}, + + /* Display : 1000x600 (GTF) */ + {VIA_RES_1000X600, CRTM1000x600, ARRAY_SIZE(CRTM1000x600)}, + + /* Display : 1024x576 (GTF) */ + {VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)}, + + /* Display : 1088x612 (GTF) */ + {VIA_RES_1088X612, CRTM1088x612, ARRAY_SIZE(CRTM1088x612)}, + + /* Display : 1152x720 (CVT) */ + {VIA_RES_1152X720, CRTM1152x720, ARRAY_SIZE(CRTM1152x720)}, + + /* Display : 1200x720 (GTF) */ + {VIA_RES_1200X720, CRTM1200x720, ARRAY_SIZE(CRTM1200x720)}, + + /* Display : 1280x600 (GTF) */ + {VIA_RES_1280X600, CRTM1280x600, ARRAY_SIZE(CRTM1280x600)}, + + /* Display : 1280x800 (CVT) */ + {VIA_RES_1280X800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)}, + + /* Display : 1280x800 (GTF) */ + /*{ M1280x800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)}, */ + + /* Display : 1280x960 */ + {VIA_RES_1280X960, CRTM1280x960, ARRAY_SIZE(CRTM1280x960)}, + + /* Display : 1280x1024 */ + {VIA_RES_1280X1024, CRTM1280x1024, ARRAY_SIZE(CRTM1280x1024)}, + + /* Display : 1360x768 (CVT) */ + {VIA_RES_1360X768, CRTM1360x768, ARRAY_SIZE(CRTM1360x768)}, + + /* Display : 1360x768 (CVT Reduce Blanking) */ + {VIA_RES_1360X768_RB, CRTM1360x768_RB, + ARRAY_SIZE(CRTM1360x768_RB)}, + + /* Display : 1366x768 */ + {VIA_RES_1366X768, CRTM1366x768, ARRAY_SIZE(CRTM1366x768)}, + + /* Display : 1368x768 (GTF) */ + /*{ M1368x768,CRTM1368x768,ARRAY_SIZE(CRTM1368x768)}, */ + /* Display : 1368x768 (GTF) */ + {VIA_RES_1368X768, CRTM1368x768, ARRAY_SIZE(CRTM1368x768)}, + + /* Display : 1440x900 (CVT) */ + {VIA_RES_1440X900, CRTM1440x900, ARRAY_SIZE(CRTM1440x900)}, + + /* Display : 1440x900 (CVT Reduce Blanking) */ + {VIA_RES_1440X900_RB, CRTM1440x900_RB, + ARRAY_SIZE(CRTM1440x900_RB)}, + + /* Display : 1440x1050 (GTF) */ + {VIA_RES_1440X1050, CRTM1440x1050, ARRAY_SIZE(CRTM1440x1050)}, + + /* Display : 1400x1050 (CVT Reduce Blanking) */ + {VIA_RES_1400X1050_RB, CRTM1400x1050_RB, + ARRAY_SIZE(CRTM1400x1050_RB)}, + + /* Display : 1600x900 (CVT) */ + {VIA_RES_1600X900, CRTM1600x900, ARRAY_SIZE(CRTM1600x900)}, + + /* Display : 1600x900 (CVT Reduce Blanking) */ + {VIA_RES_1600X900_RB, CRTM1600x900_RB, + ARRAY_SIZE(CRTM1600x900_RB)}, + + /* Display : 1600x1024 (GTF) */ + {VIA_RES_1600X1024, CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)}, + + /* Display : 1600x1200 */ + {VIA_RES_1600X1200, CRTM1600x1200, ARRAY_SIZE(CRTM1600x1200)}, + + /* Display : 1680x1050 (CVT) */ + {VIA_RES_1680X1050, CRTM1680x1050, ARRAY_SIZE(CRTM1680x1050)}, + + /* Display : 1680x1050 (CVT Reduce Blanking) */ + {VIA_RES_1680X1050_RB, CRTM1680x1050_RB, + ARRAY_SIZE(CRTM1680x1050_RB)}, + + /* Display : 1792x1344 (DMT) */ + {VIA_RES_1792X1344, CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)}, + + /* Display : 1856x1392 (DMT) */ + {VIA_RES_1856X1392, CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)}, + + /* Display : 1920x1440 */ + {VIA_RES_1920X1440, CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)}, + + /* Display : 2048x1536 */ + {VIA_RES_2048X1536, CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)}, + + /* Display : 1280x720 */ + {VIA_RES_1280X720, CRTM1280x720, ARRAY_SIZE(CRTM1280x720)}, + + /* Display : 1920x1080 (CVT) */ + {VIA_RES_1920X1080, CRTM1920x1080, ARRAY_SIZE(CRTM1920x1080)}, + + /* Display : 1920x1080 (CVT Reduce Blanking) */ + {VIA_RES_1920X1080_RB, CRTM1920x1080_RB, + ARRAY_SIZE(CRTM1920x1080_RB)}, + + /* Display : 1920x1200 (CVT) */ + {VIA_RES_1920X1200, CRTM1920x1200, ARRAY_SIZE(CRTM1920x1200)}, + + /* Display : 1920x1200 (CVT Reduce Blanking) */ + {VIA_RES_1920X1200_RB, CRTM1920x1200_RB, + ARRAY_SIZE(CRTM1920x1200_RB)}, + + /* Display : 1400x1050 (CVT) */ + {VIA_RES_1400X1050, CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)} +}; +struct crt_mode_table CEAM1280x720[] = { + {REFRESH_60, CLK_74_270M, M1280X720_CEA_R60_HSP, + M1280X720_CEA_R60_VSP, + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {1650, 1280, 1280, 370, 1390, 40, 750, 720, 720, 30, 725, 5} } +}; +struct crt_mode_table CEAM1920x1080[] = { + {REFRESH_60, CLK_148_500M, M1920X1080_CEA_R60_HSP, + M1920X1080_CEA_R60_VSP, + /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ + {2200, 1920, 1920, 300, 2008, 44, 1125, 1080, 1080, 45, 1084, 5} } +}; +struct VideoModeTable CEA_HDMI_Modes[] = { + /* Display : 1280x720 */ + {VIA_RES_1280X720, CEAM1280x720, ARRAY_SIZE(CEAM1280x720)}, + {VIA_RES_1920X1080, CEAM1920x1080, ARRAY_SIZE(CEAM1920x1080)} +}; diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h new file mode 100644 index 00000000000..1a5de50a23a --- /dev/null +++ b/drivers/video/via/viamode.h @@ -0,0 +1,177 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VIAMODE_H__ +#define __VIAMODE_H__ + +#include "global.h" + +struct VPITTable { + unsigned char Misc; + unsigned char SR[StdSR]; + unsigned char GR[StdGR]; + unsigned char AR[StdAR]; +}; + +struct VideoModeTable { + int ModeIndex; + struct crt_mode_table *crtc; + int mode_array; +}; + +struct patch_table { + int mode_index; + int table_length; + struct io_reg *io_reg_table; +}; + +struct res_map_refresh { + int hres; + int vres; + int pixclock; + int vmode_refresh; +}; + +#define NUM_TOTAL_RES_MAP_REFRESH ARRAY_SIZE(res_map_refresh_tbl) +#define NUM_TOTAL_CEA_MODES ARRAY_SIZE(CEA_HDMI_Modes) +#define NUM_TOTAL_CN400_ModeXregs ARRAY_SIZE(CN400_ModeXregs) +#define NUM_TOTAL_CN700_ModeXregs ARRAY_SIZE(CN700_ModeXregs) +#define NUM_TOTAL_KM400_ModeXregs ARRAY_SIZE(KM400_ModeXregs) +#define NUM_TOTAL_CX700_ModeXregs ARRAY_SIZE(CX700_ModeXregs) +#define NUM_TOTAL_VX800_ModeXregs ARRAY_SIZE(VX800_ModeXregs) +#define NUM_TOTAL_CLE266_ModeXregs ARRAY_SIZE(CLE266_ModeXregs) +#define NUM_TOTAL_PATCH_MODE ARRAY_SIZE(res_patch_table) +#define NUM_TOTAL_MODETABLE ARRAY_SIZE(CLE266Modes) + +/********************/ +/* Mode Table */ +/********************/ + +/* 480x640 */ +extern struct crt_mode_table CRTM480x640[1]; +/* 640x480*/ +extern struct crt_mode_table CRTM640x480[5]; +/*720x480 (GTF)*/ +extern struct crt_mode_table CRTM720x480[1]; +/*720x576 (GTF)*/ +extern struct crt_mode_table CRTM720x576[1]; +/* 800x480 (CVT) */ +extern struct crt_mode_table CRTM800x480[1]; +/* 800x600*/ +extern struct crt_mode_table CRTM800x600[5]; +/* 848x480 (CVT) */ +extern struct crt_mode_table CRTM848x480[1]; +/*856x480 (GTF) convert to 852x480*/ +extern struct crt_mode_table CRTM852x480[1]; +/*1024x512 (GTF)*/ +extern struct crt_mode_table CRTM1024x512[1]; +/* 1024x600*/ +extern struct crt_mode_table CRTM1024x600[1]; +/* 1024x768*/ +extern struct crt_mode_table CRTM1024x768[4]; +/* 1152x864*/ +extern struct crt_mode_table CRTM1152x864[1]; +/* 1280x720 (HDMI 720P)*/ +extern struct crt_mode_table CRTM1280x720[2]; +/*1280x768 (GTF)*/ +extern struct crt_mode_table CRTM1280x768[2]; +/* 1280x800 (CVT) */ +extern struct crt_mode_table CRTM1280x800[1]; +/*1280x960*/ +extern struct crt_mode_table CRTM1280x960[1]; +/* 1280x1024*/ +extern struct crt_mode_table CRTM1280x1024[3]; +/* 1368x768 (GTF) */ +extern struct crt_mode_table CRTM1368x768[1]; +/*1440x1050 (GTF)*/ +extern struct crt_mode_table CRTM1440x1050[1]; +/* 1600x1200*/ +extern struct crt_mode_table CRTM1600x1200[2]; +/* 1680x1050 (CVT) */ +extern struct crt_mode_table CRTM1680x1050[2]; +/* 1680x1050 (CVT Reduce Blanking) */ +extern struct crt_mode_table CRTM1680x1050_RB[1]; +/* 1920x1080 (CVT)*/ +extern struct crt_mode_table CRTM1920x1080[1]; +/* 1920x1080 (CVT with Reduce Blanking) */ +extern struct crt_mode_table CRTM1920x1080_RB[1]; +/* 1920x1440*/ +extern struct crt_mode_table CRTM1920x1440[2]; +/* 1400x1050 (CVT) */ +extern struct crt_mode_table CRTM1400x1050[2]; +/* 1400x1050 (CVT Reduce Blanking) */ +extern struct crt_mode_table CRTM1400x1050_RB[1]; +/* 960x600 (CVT) */ +extern struct crt_mode_table CRTM960x600[1]; +/* 1000x600 (GTF) */ +extern struct crt_mode_table CRTM1000x600[1]; +/* 1024x576 (GTF) */ +extern struct crt_mode_table CRTM1024x576[1]; +/* 1088x612 (CVT) */ +extern struct crt_mode_table CRTM1088x612[1]; +/* 1152x720 (CVT) */ +extern struct crt_mode_table CRTM1152x720[1]; +/* 1200x720 (GTF) */ +extern struct crt_mode_table CRTM1200x720[1]; +/* 1280x600 (GTF) */ +extern struct crt_mode_table CRTM1280x600[1]; +/* 1360x768 (CVT) */ +extern struct crt_mode_table CRTM1360x768[1]; +/* 1360x768 (CVT Reduce Blanking) */ +extern struct crt_mode_table CRTM1360x768_RB[1]; +/* 1366x768 (GTF) */ +extern struct crt_mode_table CRTM1366x768[2]; +/* 1440x900 (CVT) */ +extern struct crt_mode_table CRTM1440x900[2]; +/* 1440x900 (CVT Reduce Blanking) */ +extern struct crt_mode_table CRTM1440x900_RB[1]; +/* 1600x900 (CVT) */ +extern struct crt_mode_table CRTM1600x900[1]; +/* 1600x900 (CVT Reduce Blanking) */ +extern struct crt_mode_table CRTM1600x900_RB[1]; +/* 1600x1024 (GTF) */ +extern struct crt_mode_table CRTM1600x1024[1]; +/* 1792x1344 (DMT) */ +extern struct crt_mode_table CRTM1792x1344[1]; +/* 1856x1392 (DMT) */ +extern struct crt_mode_table CRTM1856x1392[1]; +/* 1920x1200 (CVT) */ +extern struct crt_mode_table CRTM1920x1200[1]; +/* 1920x1200 (CVT with Reduce Blanking) */ +extern struct crt_mode_table CRTM1920x1200_RB[1]; +/* 2048x1536 (CVT) */ +extern struct crt_mode_table CRTM2048x1536[1]; +extern struct VideoModeTable CLE266Modes[47]; +extern struct crt_mode_table CEAM1280x720[1]; +extern struct crt_mode_table CEAM1920x1080[1]; +extern struct VideoModeTable CEA_HDMI_Modes[2]; + +extern struct res_map_refresh res_map_refresh_tbl[61]; +extern struct io_reg CN400_ModeXregs[52]; +extern struct io_reg CN700_ModeXregs[66]; +extern struct io_reg KM400_ModeXregs[55]; +extern struct io_reg CX700_ModeXregs[58]; +extern struct io_reg VX800_ModeXregs[58]; +extern struct io_reg CLE266_ModeXregs[32]; +extern struct io_reg PM1024x768[2]; +extern struct patch_table res_patch_table[1]; +extern struct VPITTable VPIT; +#endif /* __VIAMODE_H__ */ diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c new file mode 100644 index 00000000000..322a9f99355 --- /dev/null +++ b/drivers/video/via/vt1636.c @@ -0,0 +1,306 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "global.h" + +u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, + u8 index) +{ + u8 data; + + viaparinfo->i2c_stuff.i2c_port = plvds_chip_info->i2c_port; + viafb_i2c_readbyte(plvds_chip_info->lvds_chip_slave_addr, index, &data); + + return data; +} + +void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information + *plvds_chip_info, struct IODATA io_data) +{ + int index, data; + + viaparinfo->i2c_stuff.i2c_port = plvds_chip_info->i2c_port; + + index = io_data.Index; + data = viafb_gpio_i2c_read_lvds(plvds_setting_info, plvds_chip_info, + index); + data = (data & (~io_data.Mask)) | io_data.Data; + + viafb_i2c_writebyte(plvds_chip_info->lvds_chip_slave_addr, index, data); +} + +void viafb_init_lvds_vt1636(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information *plvds_chip_info) +{ + int reg_num, i; + + /* Common settings: */ + reg_num = ARRAY_SIZE(COMMON_INIT_TBL_VT1636); + + for (i = 0; i < reg_num; i++) { + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, + plvds_chip_info, + COMMON_INIT_TBL_VT1636[i]); + } + + /* Input Data Mode Select */ + if (plvds_setting_info->device_lcd_dualedge) { + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, + plvds_chip_info, + DUAL_CHANNEL_ENABLE_TBL_VT1636[0]); + } else { + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, + plvds_chip_info, + SINGLE_CHANNEL_ENABLE_TBL_VT1636[0]); + } + + if (plvds_setting_info->LCDDithering) { + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, + plvds_chip_info, + DITHERING_ENABLE_TBL_VT1636[0]); + } else { + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, + plvds_chip_info, + DITHERING_DISABLE_TBL_VT1636[0]); + } +} + +void viafb_enable_lvds_vt1636(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info, + VDD_ON_TBL_VT1636[0]); + + /* Pad on: */ + switch (plvds_chip_info->output_interface) { + case INTERFACE_DVP0: + { + viafb_write_reg_mask(SR1E, VIASR, 0xC0, 0xC0); + break; + } + + case INTERFACE_DVP1: + { + viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30); + break; + } + + case INTERFACE_DFP_LOW: + { + viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x03); + break; + } + + case INTERFACE_DFP_HIGH: + { + viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x0C); + break; + } + + } +} + +void viafb_disable_lvds_vt1636(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info, + VDD_OFF_TBL_VT1636[0]); + + /* Pad off: */ + switch (plvds_chip_info->output_interface) { + case INTERFACE_DVP0: + { + viafb_write_reg_mask(SR1E, VIASR, 0x00, 0xC0); + break; + } + + case INTERFACE_DVP1: + { + viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30); + break; + } + + case INTERFACE_DFP_LOW: + { + viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x03); + break; + } + + case INTERFACE_DFP_HIGH: + { + viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0C); + break; + } + + } +} + +bool viafb_lvds_identify_vt1636(void) +{ + u8 Buffer[2]; + + DEBUG_MSG(KERN_INFO "viafb_lvds_identify_vt1636.\n"); + + /* Sense VT1636 LVDS Transmiter */ + viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr = + VT1636_LVDS_I2C_ADDR; + + /* Check vendor ID first: */ + viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info. + lvds_chip_slave_addr, + 0x00, &Buffer[0]); + viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info. + lvds_chip_slave_addr, + 0x01, &Buffer[1]); + + if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11))) + return false; + + /* Check Chip ID: */ + viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info. + lvds_chip_slave_addr, + 0x02, &Buffer[0]); + viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info. + lvds_chip_slave_addr, + 0x03, &Buffer[1]); + if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) { + viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = + VT1636_LVDS; + return true; + } + + return false; +} + +static int get_clk_range_index(u32 Clk) +{ + if (Clk < DPA_CLK_30M) + return DPA_CLK_RANGE_30M; + else if (Clk < DPA_CLK_50M) + return DPA_CLK_RANGE_30_50M; + else if (Clk < DPA_CLK_70M) + return DPA_CLK_RANGE_50_70M; + else if (Clk < DPA_CLK_100M) + return DPA_CLK_RANGE_70_100M; + else if (Clk < DPA_CLK_150M) + return DPA_CLK_RANGE_100_150M; + else + return DPA_CLK_RANGE_150M; +} + +static int get_lvds_dpa_setting_index(int panel_size_id, + struct VT1636_DPA_SETTING *p_vt1636_dpasetting_tbl, + int tbl_size) +{ + int i; + + for (i = 0; i < tbl_size; i++) { + if (panel_size_id == p_vt1636_dpasetting_tbl->PanelSizeID) + return i; + + p_vt1636_dpasetting_tbl++; + } + + return 0; +} + +static void set_dpa_vt1636(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, + struct VT1636_DPA_SETTING *p_vt1636_dpa_setting) +{ + struct IODATA io_data; + + io_data.Index = 0x09; + io_data.Mask = 0x1F; + io_data.Data = p_vt1636_dpa_setting->CLK_SEL_ST1; + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, + plvds_chip_info, io_data); + + io_data.Index = 0x08; + io_data.Mask = 0x0F; + io_data.Data = p_vt1636_dpa_setting->CLK_SEL_ST2; + viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info, + io_data); +} + +void viafb_vt1636_patch_skew_on_vt3324( + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + int index, size; + + DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3324.\n"); + + /* Graphics DPA settings: */ + index = get_clk_range_index(plvds_setting_info->vclk); + viafb_set_dpa_gfx(plvds_chip_info->output_interface, + &GFX_DPA_SETTING_TBL_VT3324[index]); + + /* LVDS Transmitter DPA settings: */ + size = ARRAY_SIZE(VT1636_DPA_SETTING_TBL_VT3324); + index = + get_lvds_dpa_setting_index(plvds_setting_info->lcd_panel_id, + VT1636_DPA_SETTING_TBL_VT3324, size); + set_dpa_vt1636(plvds_setting_info, plvds_chip_info, + &VT1636_DPA_SETTING_TBL_VT3324[index]); +} + +void viafb_vt1636_patch_skew_on_vt3327( + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + int index, size; + + DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3327.\n"); + + /* Graphics DPA settings: */ + index = get_clk_range_index(plvds_setting_info->vclk); + viafb_set_dpa_gfx(plvds_chip_info->output_interface, + &GFX_DPA_SETTING_TBL_VT3327[index]); + + /* LVDS Transmitter DPA settings: */ + size = ARRAY_SIZE(VT1636_DPA_SETTING_TBL_VT3327); + index = + get_lvds_dpa_setting_index(plvds_setting_info->lcd_panel_id, + VT1636_DPA_SETTING_TBL_VT3327, size); + set_dpa_vt1636(plvds_setting_info, plvds_chip_info, + &VT1636_DPA_SETTING_TBL_VT3327[index]); +} + +void viafb_vt1636_patch_skew_on_vt3364( + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) +{ + int index; + + DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3364.\n"); + + /* Graphics DPA settings: */ + index = get_clk_range_index(plvds_setting_info->vclk); + viafb_set_dpa_gfx(plvds_chip_info->output_interface, + &GFX_DPA_SETTING_TBL_VT3364[index]); +} diff --git a/drivers/video/via/vt1636.h b/drivers/video/via/vt1636.h new file mode 100644 index 00000000000..2a150c58c7e --- /dev/null +++ b/drivers/video/via/vt1636.h @@ -0,0 +1,44 @@ +/* + * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _VT1636_H_ +#define _VT1636_H_ +#include "chip.h" +bool viafb_lvds_identify_vt1636(void); +void viafb_init_lvds_vt1636(struct lvds_setting_information + *plvds_setting_info, struct lvds_chip_information *plvds_chip_info); +void viafb_enable_lvds_vt1636(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +void viafb_disable_lvds_vt1636(struct lvds_setting_information + *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +void viafb_vt1636_patch_skew_on_vt3324( + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +void viafb_vt1636_patch_skew_on_vt3327( + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); +void viafb_vt1636_patch_skew_on_vt3364( + struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); + +#endif |