Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vt8623fb: new framebuffer driver for VIA VT8623

This patch adds fbdev driver for graphics core in VIA VT8623

[adaplas@gmail.com: build fixes]
Signed-off-by: Ondrej Zajicek <santiago@crfreenet.org>
Signed-off-by: Antonino Daplas <adaplas@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Ondrej Zajicek and committed by
Linus Torvalds
558b7bd8 c3c117f0

+1005
+64
Documentation/fb/vt8623fb.txt
··· 1 + 2 + vt8623fb - fbdev driver for graphics core in VIA VT8623 chipset 3 + =============================================================== 4 + 5 + 6 + Supported Hardware 7 + ================== 8 + 9 + VIA VT8623 [CLE266] chipset and its graphics core 10 + (known as CastleRock or Unichrome) 11 + 12 + I tested vt8623fb on VIA EPIA ML-6000 13 + 14 + 15 + Supported Features 16 + ================== 17 + 18 + * 4 bpp pseudocolor modes (with 18bit palette, two variants) 19 + * 8 bpp pseudocolor mode (with 18bit palette) 20 + * 16 bpp truecolor mode (RGB 565) 21 + * 32 bpp truecolor mode (RGB 888) 22 + * text mode (activated by bpp = 0) 23 + * doublescan mode variant (not available in text mode) 24 + * panning in both directions 25 + * suspend/resume support 26 + * DPMS support 27 + 28 + Text mode is supported even in higher resolutions, but there is limitation to 29 + lower pixclocks (maximum about 100 MHz). This limitation is not enforced by 30 + driver. Text mode supports 8bit wide fonts only (hardware limitation) and 31 + 16bit tall fonts (driver limitation). 32 + 33 + There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with 34 + packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode 35 + with interleaved planes (1 byte interleave), MSB first. Both modes support 36 + 8bit wide fonts only (driver limitation). 37 + 38 + Suspend/resume works on systems that initialize video card during resume and 39 + if device is active (for example used by fbcon). 40 + 41 + 42 + Missing Features 43 + ================ 44 + (alias TODO list) 45 + 46 + * secondary (not initialized by BIOS) device support 47 + * MMIO support 48 + * interlaced mode variant 49 + * support for fontwidths != 8 in 4 bpp modes 50 + * support for fontheight != 16 in text mode 51 + * hardware cursor 52 + * video overlay support 53 + * vsync synchronization 54 + * acceleration support (8514-like 2D, busmaster transfers) 55 + 56 + 57 + Known bugs 58 + ========== 59 + 60 + * cursor disable in text mode doesn't work 61 + 62 + 63 + -- 64 + Ondrej Zajicek <santiago@crfreenet.org>
+14
drivers/video/Kconfig
··· 1348 1348 Please read the <file:Documentation/fb/README-sstfb.txt> for supported 1349 1349 options and other important info support. 1350 1350 1351 + config FB_VT8623 1352 + tristate "VIA VT8623 support" 1353 + depends on FB && PCI 1354 + select FB_CFB_FILLRECT 1355 + select FB_CFB_COPYAREA 1356 + select FB_CFB_IMAGEBLIT 1357 + select FB_TILEBLITTING 1358 + select FB_SVGALIB 1359 + select VGASTATE 1360 + select FONT_8x16 if FRAMEBUFFER_CONSOLE 1361 + ---help--- 1362 + Driver for CastleRock integrated graphics core in the 1363 + VIA VT8623 [Apollo CLE266] chipset. 1364 + 1351 1365 config FB_CYBLA 1352 1366 tristate "Cyberblade/i1 support" 1353 1367 depends on FB && PCI && X86_32 && !64BIT
+1
drivers/video/Makefile
··· 54 54 obj-$(CONFIG_FB_CT65550) += chipsfb.o 55 55 obj-$(CONFIG_FB_IMSTT) += imsttfb.o 56 56 obj-$(CONFIG_FB_FM2) += fm2fb.o 57 + obj-$(CONFIG_FB_VT8623) += vt8623fb.o 57 58 obj-$(CONFIG_FB_CYBLA) += cyblafb.o 58 59 obj-$(CONFIG_FB_TRIDENT) += tridentfb.o 59 60 obj-$(CONFIG_FB_LE80578) += vermilion/
+926
drivers/video/vt8623fb.c
··· 1 + /* 2 + * linux/drivers/video/vt8623fb.c - fbdev driver for 3 + * integrated graphic core in VIA VT8623 [CLE266] chipset 4 + * 5 + * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org> 6 + * 7 + * This file is subject to the terms and conditions of the GNU General Public 8 + * License. See the file COPYING in the main directory of this archive for 9 + * more details. 10 + * 11 + * Code is based on s3fb, some parts are from David Boucher's viafb 12 + * (http://davesdomain.org.uk/viafb/) 13 + */ 14 + 15 + #include <linux/version.h> 16 + #include <linux/module.h> 17 + #include <linux/kernel.h> 18 + #include <linux/errno.h> 19 + #include <linux/string.h> 20 + #include <linux/mm.h> 21 + #include <linux/tty.h> 22 + #include <linux/slab.h> 23 + #include <linux/delay.h> 24 + #include <linux/fb.h> 25 + #include <linux/svga.h> 26 + #include <linux/init.h> 27 + #include <linux/pci.h> 28 + #include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */ 29 + #include <video/vga.h> 30 + 31 + #ifdef CONFIG_MTRR 32 + #include <asm/mtrr.h> 33 + #endif 34 + 35 + struct vt8623fb_info { 36 + char __iomem *mmio_base; 37 + int mtrr_reg; 38 + struct vgastate state; 39 + struct mutex open_lock; 40 + unsigned int ref_count; 41 + u32 pseudo_palette[16]; 42 + }; 43 + 44 + 45 + 46 + /* ------------------------------------------------------------------------- */ 47 + 48 + static const struct svga_fb_format vt8623fb_formats[] = { 49 + { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, 50 + FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8, FB_VISUAL_PSEUDOCOLOR, 16, 16}, 51 + { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, 52 + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 16}, 53 + { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1, 54 + FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 16, 16}, 55 + { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, 56 + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8}, 57 + /* {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0, 58 + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, */ 59 + {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0, 60 + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, 61 + {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, 62 + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2}, 63 + SVGA_FORMAT_END 64 + }; 65 + 66 + static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3, 67 + 60000, 300000, 14318}; 68 + 69 + /* CRT timing register sets */ 70 + 71 + struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END}; 72 + struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END}; 73 + struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END}; 74 + struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END}; 75 + struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END}; 76 + struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END}; 77 + 78 + struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END}; 79 + struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END}; 80 + struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END}; 81 + struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END}; 82 + struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END}; 83 + struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; 84 + 85 + struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END}; 86 + struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END}; 87 + struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END}; 88 + struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END}; 89 + 90 + struct svga_timing_regs vt8623_timing_regs = { 91 + vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs, 92 + vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs, 93 + vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs, 94 + vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs, 95 + }; 96 + 97 + 98 + /* ------------------------------------------------------------------------- */ 99 + 100 + 101 + /* Module parameters */ 102 + 103 + static char *mode = "640x480-8@60"; 104 + 105 + #ifdef CONFIG_MTRR 106 + static int mtrr = 1; 107 + #endif 108 + 109 + MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>"); 110 + MODULE_LICENSE("GPL"); 111 + MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]"); 112 + 113 + module_param(mode, charp, 0644); 114 + MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)"); 115 + 116 + #ifdef CONFIG_MTRR 117 + module_param(mtrr, int, 0444); 118 + MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); 119 + #endif 120 + 121 + 122 + /* ------------------------------------------------------------------------- */ 123 + 124 + 125 + static struct fb_tile_ops vt8623fb_tile_ops = { 126 + .fb_settile = svga_settile, 127 + .fb_tilecopy = svga_tilecopy, 128 + .fb_tilefill = svga_tilefill, 129 + .fb_tileblit = svga_tileblit, 130 + .fb_tilecursor = svga_tilecursor, 131 + .fb_get_tilemax = svga_get_tilemax, 132 + }; 133 + 134 + 135 + /* ------------------------------------------------------------------------- */ 136 + 137 + 138 + /* image data is MSB-first, fb structure is MSB-first too */ 139 + static inline u32 expand_color(u32 c) 140 + { 141 + return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF; 142 + } 143 + 144 + /* vt8623fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */ 145 + static void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image) 146 + { 147 + u32 fg = expand_color(image->fg_color); 148 + u32 bg = expand_color(image->bg_color); 149 + const u8 *src1, *src; 150 + u8 __iomem *dst1; 151 + u32 __iomem *dst; 152 + u32 val; 153 + int x, y; 154 + 155 + src1 = image->data; 156 + dst1 = info->screen_base + (image->dy * info->fix.line_length) 157 + + ((image->dx / 8) * 4); 158 + 159 + for (y = 0; y < image->height; y++) { 160 + src = src1; 161 + dst = (u32 __iomem *) dst1; 162 + for (x = 0; x < image->width; x += 8) { 163 + val = *(src++) * 0x01010101; 164 + val = (val & fg) | (~val & bg); 165 + fb_writel(val, dst++); 166 + } 167 + src1 += image->width / 8; 168 + dst1 += info->fix.line_length; 169 + } 170 + } 171 + 172 + /* vt8623fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */ 173 + static void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 174 + { 175 + u32 fg = expand_color(rect->color); 176 + u8 __iomem *dst1; 177 + u32 __iomem *dst; 178 + int x, y; 179 + 180 + dst1 = info->screen_base + (rect->dy * info->fix.line_length) 181 + + ((rect->dx / 8) * 4); 182 + 183 + for (y = 0; y < rect->height; y++) { 184 + dst = (u32 __iomem *) dst1; 185 + for (x = 0; x < rect->width; x += 8) { 186 + fb_writel(fg, dst++); 187 + } 188 + dst1 += info->fix.line_length; 189 + } 190 + } 191 + 192 + 193 + /* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */ 194 + static inline u32 expand_pixel(u32 c) 195 + { 196 + return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) | 197 + ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF; 198 + } 199 + 200 + /* vt8623fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */ 201 + static void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image) 202 + { 203 + u32 fg = image->fg_color * 0x11111111; 204 + u32 bg = image->bg_color * 0x11111111; 205 + const u8 *src1, *src; 206 + u8 __iomem *dst1; 207 + u32 __iomem *dst; 208 + u32 val; 209 + int x, y; 210 + 211 + src1 = image->data; 212 + dst1 = info->screen_base + (image->dy * info->fix.line_length) 213 + + ((image->dx / 8) * 4); 214 + 215 + for (y = 0; y < image->height; y++) { 216 + src = src1; 217 + dst = (u32 __iomem *) dst1; 218 + for (x = 0; x < image->width; x += 8) { 219 + val = expand_pixel(*(src++)); 220 + val = (val & fg) | (~val & bg); 221 + fb_writel(val, dst++); 222 + } 223 + src1 += image->width / 8; 224 + dst1 += info->fix.line_length; 225 + } 226 + } 227 + 228 + static void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image) 229 + { 230 + if ((info->var.bits_per_pixel == 4) && (image->depth == 1) 231 + && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) { 232 + if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES) 233 + vt8623fb_iplan_imageblit(info, image); 234 + else 235 + vt8623fb_cfb4_imageblit(info, image); 236 + } else 237 + cfb_imageblit(info, image); 238 + } 239 + 240 + static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 241 + { 242 + if ((info->var.bits_per_pixel == 4) 243 + && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0) 244 + && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)) 245 + vt8623fb_iplan_fillrect(info, rect); 246 + else 247 + cfb_fillrect(info, rect); 248 + } 249 + 250 + 251 + /* ------------------------------------------------------------------------- */ 252 + 253 + 254 + static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock) 255 + { 256 + u16 m, n, r; 257 + u8 regval; 258 + int rv; 259 + 260 + rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node); 261 + if (rv < 0) { 262 + printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node); 263 + return; 264 + } 265 + 266 + /* Set VGA misc register */ 267 + regval = vga_r(NULL, VGA_MIS_R); 268 + vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); 269 + 270 + /* Set clock registers */ 271 + vga_wseq(NULL, 0x46, (n | (r << 6))); 272 + vga_wseq(NULL, 0x47, m); 273 + 274 + udelay(1000); 275 + 276 + /* PLL reset */ 277 + svga_wseq_mask(0x40, 0x02, 0x02); 278 + svga_wseq_mask(0x40, 0x00, 0x02); 279 + } 280 + 281 + 282 + static int vt8623fb_open(struct fb_info *info, int user) 283 + { 284 + struct vt8623fb_info *par = info->par; 285 + 286 + mutex_lock(&(par->open_lock)); 287 + if (par->ref_count == 0) { 288 + memset(&(par->state), 0, sizeof(struct vgastate)); 289 + par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; 290 + par->state.num_crtc = 0xA2; 291 + par->state.num_seq = 0x50; 292 + save_vga(&(par->state)); 293 + } 294 + 295 + par->ref_count++; 296 + mutex_unlock(&(par->open_lock)); 297 + 298 + return 0; 299 + } 300 + 301 + static int vt8623fb_release(struct fb_info *info, int user) 302 + { 303 + struct vt8623fb_info *par = info->par; 304 + 305 + mutex_lock(&(par->open_lock)); 306 + if (par->ref_count == 0) { 307 + mutex_unlock(&(par->open_lock)); 308 + return -EINVAL; 309 + } 310 + 311 + if (par->ref_count == 1) 312 + restore_vga(&(par->state)); 313 + 314 + par->ref_count--; 315 + mutex_unlock(&(par->open_lock)); 316 + 317 + return 0; 318 + } 319 + 320 + static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 321 + { 322 + int rv, mem, step; 323 + 324 + /* Find appropriate format */ 325 + rv = svga_match_format (vt8623fb_formats, var, NULL); 326 + if (rv < 0) 327 + { 328 + printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); 329 + return rv; 330 + } 331 + 332 + /* Do not allow to have real resoulution larger than virtual */ 333 + if (var->xres > var->xres_virtual) 334 + var->xres_virtual = var->xres; 335 + 336 + if (var->yres > var->yres_virtual) 337 + var->yres_virtual = var->yres; 338 + 339 + /* Round up xres_virtual to have proper alignment of lines */ 340 + step = vt8623fb_formats[rv].xresstep - 1; 341 + var->xres_virtual = (var->xres_virtual+step) & ~step; 342 + 343 + /* Check whether have enough memory */ 344 + mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; 345 + if (mem > info->screen_size) 346 + { 347 + printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); 348 + return -EINVAL; 349 + } 350 + 351 + /* Text mode is limited to 256 kB of memory */ 352 + if ((var->bits_per_pixel == 0) && (mem > (256*1024))) 353 + { 354 + printk(KERN_ERR "fb%d: text framebuffer size too large (%d kB requested, 256 kB possible)\n", info->node, mem >> 10); 355 + return -EINVAL; 356 + } 357 + 358 + rv = svga_check_timings (&vt8623_timing_regs, var, info->node); 359 + if (rv < 0) 360 + { 361 + printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); 362 + return rv; 363 + } 364 + 365 + /* Interlaced mode not supported */ 366 + if (var->vmode & FB_VMODE_INTERLACED) 367 + return -EINVAL; 368 + 369 + return 0; 370 + } 371 + 372 + 373 + static int vt8623fb_set_par(struct fb_info *info) 374 + { 375 + u32 mode, offset_value, fetch_value, screen_size; 376 + u32 bpp = info->var.bits_per_pixel; 377 + 378 + if (bpp != 0) { 379 + info->fix.ypanstep = 1; 380 + info->fix.line_length = (info->var.xres_virtual * bpp) / 8; 381 + 382 + info->flags &= ~FBINFO_MISC_TILEBLITTING; 383 + info->tileops = NULL; 384 + 385 + /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ 386 + info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0); 387 + info->pixmap.blit_y = ~(u32)0; 388 + 389 + offset_value = (info->var.xres_virtual * bpp) / 64; 390 + fetch_value = ((info->var.xres * bpp) / 128) + 4; 391 + 392 + if (bpp == 4) 393 + fetch_value = (info->var.xres / 8) + 8; /* + 0 is OK */ 394 + 395 + screen_size = info->var.yres_virtual * info->fix.line_length; 396 + } else { 397 + info->fix.ypanstep = 16; 398 + info->fix.line_length = 0; 399 + 400 + info->flags |= FBINFO_MISC_TILEBLITTING; 401 + info->tileops = &vt8623fb_tile_ops; 402 + 403 + /* supports 8x16 tiles only */ 404 + info->pixmap.blit_x = 1 << (8 - 1); 405 + info->pixmap.blit_y = 1 << (16 - 1); 406 + 407 + offset_value = info->var.xres_virtual / 16; 408 + fetch_value = (info->var.xres / 8) + 8; 409 + screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64; 410 + } 411 + 412 + info->var.xoffset = 0; 413 + info->var.yoffset = 0; 414 + info->var.activate = FB_ACTIVATE_NOW; 415 + 416 + /* Unlock registers */ 417 + svga_wseq_mask(0x10, 0x01, 0x01); 418 + svga_wcrt_mask(0x11, 0x00, 0x80); 419 + svga_wcrt_mask(0x47, 0x00, 0x01); 420 + 421 + /* Device, screen and sync off */ 422 + svga_wseq_mask(0x01, 0x20, 0x20); 423 + svga_wcrt_mask(0x36, 0x30, 0x30); 424 + svga_wcrt_mask(0x17, 0x00, 0x80); 425 + 426 + /* Set default values */ 427 + svga_set_default_gfx_regs(); 428 + svga_set_default_atc_regs(); 429 + svga_set_default_seq_regs(); 430 + svga_set_default_crt_regs(); 431 + svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF); 432 + svga_wcrt_multi(vt8623_start_address_regs, 0); 433 + 434 + svga_wcrt_multi(vt8623_offset_regs, offset_value); 435 + svga_wseq_multi(vt8623_fetch_count_regs, fetch_value); 436 + 437 + if (info->var.vmode & FB_VMODE_DOUBLE) 438 + svga_wcrt_mask(0x09, 0x80, 0x80); 439 + else 440 + svga_wcrt_mask(0x09, 0x00, 0x80); 441 + 442 + svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus 443 + svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus 444 + svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold 445 + vga_wseq(NULL, 0x17, 0x1F); // FIFO depth 446 + vga_wseq(NULL, 0x18, 0x4E); 447 + svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ? 448 + 449 + vga_wcrt(NULL, 0x32, 0x00); 450 + vga_wcrt(NULL, 0x34, 0x00); 451 + vga_wcrt(NULL, 0x6A, 0x80); 452 + vga_wcrt(NULL, 0x6A, 0xC0); 453 + 454 + vga_wgfx(NULL, 0x20, 0x00); 455 + vga_wgfx(NULL, 0x21, 0x00); 456 + vga_wgfx(NULL, 0x22, 0x00); 457 + 458 + /* Set SR15 according to number of bits per pixel */ 459 + mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix)); 460 + switch (mode) { 461 + case 0: 462 + pr_debug("fb%d: text mode\n", info->node); 463 + svga_set_textmode_vga_regs(); 464 + svga_wseq_mask(0x15, 0x00, 0xFE); 465 + svga_wcrt_mask(0x11, 0x60, 0x70); 466 + break; 467 + case 1: 468 + pr_debug("fb%d: 4 bit pseudocolor\n", info->node); 469 + vga_wgfx(NULL, VGA_GFX_MODE, 0x40); 470 + svga_wseq_mask(0x15, 0x20, 0xFE); 471 + svga_wcrt_mask(0x11, 0x00, 0x70); 472 + break; 473 + case 2: 474 + pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); 475 + svga_wseq_mask(0x15, 0x00, 0xFE); 476 + svga_wcrt_mask(0x11, 0x00, 0x70); 477 + break; 478 + case 3: 479 + pr_debug("fb%d: 8 bit pseudocolor\n", info->node); 480 + svga_wseq_mask(0x15, 0x22, 0xFE); 481 + break; 482 + case 4: 483 + pr_debug("fb%d: 5/6/5 truecolor\n", info->node); 484 + svga_wseq_mask(0x15, 0xB6, 0xFE); 485 + break; 486 + case 5: 487 + pr_debug("fb%d: 8/8/8 truecolor\n", info->node); 488 + svga_wseq_mask(0x15, 0xAE, 0xFE); 489 + break; 490 + default: 491 + printk(KERN_ERR "vt8623fb: unsupported mode - bug\n"); 492 + return (-EINVAL); 493 + } 494 + 495 + vt8623_set_pixclock(info, info->var.pixclock); 496 + svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1, 497 + (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1, 498 + 1, info->node); 499 + 500 + memset_io(info->screen_base, 0x00, screen_size); 501 + 502 + /* Device and screen back on */ 503 + svga_wcrt_mask(0x17, 0x80, 0x80); 504 + svga_wcrt_mask(0x36, 0x00, 0x30); 505 + svga_wseq_mask(0x01, 0x00, 0x20); 506 + 507 + return 0; 508 + } 509 + 510 + 511 + static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 512 + u_int transp, struct fb_info *fb) 513 + { 514 + switch (fb->var.bits_per_pixel) { 515 + case 0: 516 + case 4: 517 + if (regno >= 16) 518 + return -EINVAL; 519 + 520 + outb(0x0F, VGA_PEL_MSK); 521 + outb(regno, VGA_PEL_IW); 522 + outb(red >> 10, VGA_PEL_D); 523 + outb(green >> 10, VGA_PEL_D); 524 + outb(blue >> 10, VGA_PEL_D); 525 + break; 526 + case 8: 527 + if (regno >= 256) 528 + return -EINVAL; 529 + 530 + outb(0xFF, VGA_PEL_MSK); 531 + outb(regno, VGA_PEL_IW); 532 + outb(red >> 10, VGA_PEL_D); 533 + outb(green >> 10, VGA_PEL_D); 534 + outb(blue >> 10, VGA_PEL_D); 535 + break; 536 + case 16: 537 + if (regno >= 16) 538 + return 0; 539 + 540 + if (fb->var.green.length == 5) 541 + ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | 542 + ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11); 543 + else if (fb->var.green.length == 6) 544 + ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) | 545 + ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); 546 + else 547 + return -EINVAL; 548 + break; 549 + case 24: 550 + case 32: 551 + if (regno >= 16) 552 + return 0; 553 + 554 + /* ((transp & 0xFF00) << 16) */ 555 + ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) | 556 + (green & 0xFF00) | ((blue & 0xFF00) >> 8); 557 + break; 558 + default: 559 + return -EINVAL; 560 + } 561 + 562 + return 0; 563 + } 564 + 565 + 566 + static int vt8623fb_blank(int blank_mode, struct fb_info *info) 567 + { 568 + switch (blank_mode) { 569 + case FB_BLANK_UNBLANK: 570 + pr_debug("fb%d: unblank\n", info->node); 571 + svga_wcrt_mask(0x36, 0x00, 0x30); 572 + svga_wseq_mask(0x01, 0x00, 0x20); 573 + break; 574 + case FB_BLANK_NORMAL: 575 + pr_debug("fb%d: blank\n", info->node); 576 + svga_wcrt_mask(0x36, 0x00, 0x30); 577 + svga_wseq_mask(0x01, 0x20, 0x20); 578 + break; 579 + case FB_BLANK_HSYNC_SUSPEND: 580 + pr_debug("fb%d: DPMS standby (hsync off)\n", info->node); 581 + svga_wcrt_mask(0x36, 0x10, 0x30); 582 + svga_wseq_mask(0x01, 0x20, 0x20); 583 + break; 584 + case FB_BLANK_VSYNC_SUSPEND: 585 + pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node); 586 + svga_wcrt_mask(0x36, 0x20, 0x30); 587 + svga_wseq_mask(0x01, 0x20, 0x20); 588 + break; 589 + case FB_BLANK_POWERDOWN: 590 + pr_debug("fb%d: DPMS off (no sync)\n", info->node); 591 + svga_wcrt_mask(0x36, 0x30, 0x30); 592 + svga_wseq_mask(0x01, 0x20, 0x20); 593 + break; 594 + } 595 + 596 + return 0; 597 + } 598 + 599 + 600 + static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 601 + { 602 + unsigned int offset; 603 + 604 + /* Calculate the offset */ 605 + if (var->bits_per_pixel == 0) { 606 + offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset; 607 + offset = offset >> 3; 608 + } else { 609 + offset = (var->yoffset * info->fix.line_length) + 610 + (var->xoffset * var->bits_per_pixel / 8); 611 + offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1); 612 + } 613 + 614 + /* Set the offset */ 615 + svga_wcrt_multi(vt8623_start_address_regs, offset); 616 + 617 + return 0; 618 + } 619 + 620 + 621 + /* ------------------------------------------------------------------------- */ 622 + 623 + 624 + /* Frame buffer operations */ 625 + 626 + static struct fb_ops vt8623fb_ops = { 627 + .owner = THIS_MODULE, 628 + .fb_open = vt8623fb_open, 629 + .fb_release = vt8623fb_release, 630 + .fb_check_var = vt8623fb_check_var, 631 + .fb_set_par = vt8623fb_set_par, 632 + .fb_setcolreg = vt8623fb_setcolreg, 633 + .fb_blank = vt8623fb_blank, 634 + .fb_pan_display = vt8623fb_pan_display, 635 + .fb_fillrect = vt8623fb_fillrect, 636 + .fb_copyarea = cfb_copyarea, 637 + .fb_imageblit = vt8623fb_imageblit, 638 + }; 639 + 640 + 641 + /* PCI probe */ 642 + 643 + static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) 644 + { 645 + struct fb_info *info; 646 + struct vt8623fb_info *par; 647 + unsigned int memsize1, memsize2; 648 + int rc; 649 + 650 + /* Ignore secondary VGA device because there is no VGA arbitration */ 651 + if (! svga_primary_device(dev)) { 652 + dev_info(&(dev->dev), "ignoring secondary device\n"); 653 + return -ENODEV; 654 + } 655 + 656 + /* Allocate and fill driver data structure */ 657 + info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL); 658 + if (! info) { 659 + dev_err(&(dev->dev), "cannot allocate memory\n"); 660 + return -ENOMEM; 661 + } 662 + 663 + par = info->par; 664 + mutex_init(&par->open_lock); 665 + 666 + info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN; 667 + info->fbops = &vt8623fb_ops; 668 + 669 + /* Prepare PCI device */ 670 + 671 + rc = pci_enable_device(dev); 672 + if (rc < 0) { 673 + dev_err(&(dev->dev), "cannot enable PCI device\n"); 674 + goto err_enable_device; 675 + } 676 + 677 + rc = pci_request_regions(dev, "vt8623fb"); 678 + if (rc < 0) { 679 + dev_err(&(dev->dev), "cannot reserve framebuffer region\n"); 680 + goto err_request_regions; 681 + } 682 + 683 + info->fix.smem_start = pci_resource_start(dev, 0); 684 + info->fix.smem_len = pci_resource_len(dev, 0); 685 + info->fix.mmio_start = pci_resource_start(dev, 1); 686 + info->fix.mmio_len = pci_resource_len(dev, 1); 687 + 688 + /* Map physical IO memory address into kernel space */ 689 + info->screen_base = pci_iomap(dev, 0, 0); 690 + if (! info->screen_base) { 691 + rc = -ENOMEM; 692 + dev_err(&(dev->dev), "iomap for framebuffer failed\n"); 693 + goto err_iomap_1; 694 + } 695 + 696 + par->mmio_base = pci_iomap(dev, 1, 0); 697 + if (! par->mmio_base) { 698 + rc = -ENOMEM; 699 + dev_err(&(dev->dev), "iomap for MMIO failed\n"); 700 + goto err_iomap_2; 701 + } 702 + 703 + /* Find how many physical memory there is on card */ 704 + memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1; 705 + memsize2 = vga_rseq(NULL, 0x39) << 2; 706 + 707 + if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2)) 708 + info->screen_size = memsize1 << 20; 709 + else { 710 + dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2); 711 + info->screen_size = 16 << 20; 712 + } 713 + 714 + info->fix.smem_len = info->screen_size; 715 + strcpy(info->fix.id, "VIA VT8623"); 716 + info->fix.type = FB_TYPE_PACKED_PIXELS; 717 + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 718 + info->fix.ypanstep = 0; 719 + info->fix.accel = FB_ACCEL_NONE; 720 + info->pseudo_palette = (void*)par->pseudo_palette; 721 + 722 + /* Prepare startup mode */ 723 + 724 + rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8); 725 + if (! ((rc == 1) || (rc == 2))) { 726 + rc = -EINVAL; 727 + dev_err(&(dev->dev), "mode %s not found\n", mode); 728 + goto err_find_mode; 729 + } 730 + 731 + rc = fb_alloc_cmap(&info->cmap, 256, 0); 732 + if (rc < 0) { 733 + dev_err(&(dev->dev), "cannot allocate colormap\n"); 734 + goto err_alloc_cmap; 735 + } 736 + 737 + rc = register_framebuffer(info); 738 + if (rc < 0) { 739 + dev_err(&(dev->dev), "cannot register framebugger\n"); 740 + goto err_reg_fb; 741 + } 742 + 743 + printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id, 744 + pci_name(dev), info->fix.smem_len >> 20); 745 + 746 + /* Record a reference to the driver data */ 747 + pci_set_drvdata(dev, info); 748 + 749 + #ifdef CONFIG_MTRR 750 + if (mtrr) { 751 + par->mtrr_reg = -1; 752 + par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); 753 + } 754 + #endif 755 + 756 + return 0; 757 + 758 + /* Error handling */ 759 + err_reg_fb: 760 + fb_dealloc_cmap(&info->cmap); 761 + err_alloc_cmap: 762 + err_find_mode: 763 + pci_iounmap(dev, par->mmio_base); 764 + err_iomap_2: 765 + pci_iounmap(dev, info->screen_base); 766 + err_iomap_1: 767 + pci_release_regions(dev); 768 + err_request_regions: 769 + /* pci_disable_device(dev); */ 770 + err_enable_device: 771 + framebuffer_release(info); 772 + return rc; 773 + } 774 + 775 + /* PCI remove */ 776 + 777 + static void __devexit vt8623_pci_remove(struct pci_dev *dev) 778 + { 779 + struct fb_info *info = pci_get_drvdata(dev); 780 + struct vt8623fb_info *par = info->par; 781 + 782 + if (info) { 783 + #ifdef CONFIG_MTRR 784 + if (par->mtrr_reg >= 0) { 785 + mtrr_del(par->mtrr_reg, 0, 0); 786 + par->mtrr_reg = -1; 787 + } 788 + #endif 789 + 790 + unregister_framebuffer(info); 791 + fb_dealloc_cmap(&info->cmap); 792 + 793 + pci_iounmap(dev, info->screen_base); 794 + pci_iounmap(dev, par->mmio_base); 795 + pci_release_regions(dev); 796 + /* pci_disable_device(dev); */ 797 + 798 + pci_set_drvdata(dev, NULL); 799 + framebuffer_release(info); 800 + } 801 + } 802 + 803 + 804 + #ifdef CONFIG_PM 805 + /* PCI suspend */ 806 + 807 + static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state) 808 + { 809 + struct fb_info *info = pci_get_drvdata(dev); 810 + struct vt8623fb_info *par = info->par; 811 + 812 + dev_info(&(dev->dev), "suspend\n"); 813 + 814 + acquire_console_sem(); 815 + mutex_lock(&(par->open_lock)); 816 + 817 + if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) { 818 + mutex_unlock(&(par->open_lock)); 819 + release_console_sem(); 820 + return 0; 821 + } 822 + 823 + fb_set_suspend(info, 1); 824 + 825 + pci_save_state(dev); 826 + pci_disable_device(dev); 827 + pci_set_power_state(dev, pci_choose_state(dev, state)); 828 + 829 + mutex_unlock(&(par->open_lock)); 830 + release_console_sem(); 831 + 832 + return 0; 833 + } 834 + 835 + 836 + /* PCI resume */ 837 + 838 + static int vt8623_pci_resume(struct pci_dev* dev) 839 + { 840 + struct fb_info *info = pci_get_drvdata(dev); 841 + struct vt8623fb_info *par = info->par; 842 + 843 + dev_info(&(dev->dev), "resume\n"); 844 + 845 + acquire_console_sem(); 846 + mutex_lock(&(par->open_lock)); 847 + 848 + if (par->ref_count == 0) { 849 + mutex_unlock(&(par->open_lock)); 850 + release_console_sem(); 851 + return 0; 852 + } 853 + 854 + pci_set_power_state(dev, PCI_D0); 855 + pci_restore_state(dev); 856 + 857 + if (pci_enable_device(dev)) 858 + goto fail; 859 + 860 + pci_set_master(dev); 861 + 862 + vt8623fb_set_par(info); 863 + fb_set_suspend(info, 0); 864 + 865 + mutex_unlock(&(par->open_lock)); 866 + fail: 867 + release_console_sem(); 868 + 869 + return 0; 870 + } 871 + #else 872 + #define vt8623_pci_suspend NULL 873 + #define vt8623_pci_resume NULL 874 + #endif /* CONFIG_PM */ 875 + 876 + /* List of boards that we are trying to support */ 877 + 878 + static struct pci_device_id vt8623_devices[] __devinitdata = { 879 + {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)}, 880 + {0, 0, 0, 0, 0, 0, 0} 881 + }; 882 + 883 + MODULE_DEVICE_TABLE(pci, vt8623_devices); 884 + 885 + static struct pci_driver vt8623fb_pci_driver = { 886 + .name = "vt8623fb", 887 + .id_table = vt8623_devices, 888 + .probe = vt8623_pci_probe, 889 + .remove = __devexit_p(vt8623_pci_remove), 890 + .suspend = vt8623_pci_suspend, 891 + .resume = vt8623_pci_resume, 892 + }; 893 + 894 + /* Cleanup */ 895 + 896 + static void __exit vt8623fb_cleanup(void) 897 + { 898 + pr_debug("vt8623fb: cleaning up\n"); 899 + pci_unregister_driver(&vt8623fb_pci_driver); 900 + } 901 + 902 + /* Driver Initialisation */ 903 + 904 + int __init vt8623fb_init(void) 905 + { 906 + 907 + #ifndef MODULE 908 + char *option = NULL; 909 + 910 + if (fb_get_options("vt8623fb", &option)) 911 + return -ENODEV; 912 + 913 + if (option && *option) 914 + mode = option; 915 + #endif 916 + 917 + pr_debug("vt8623fb: initializing\n"); 918 + return pci_register_driver(&vt8623fb_pci_driver); 919 + } 920 + 921 + /* ------------------------------------------------------------------------- */ 922 + 923 + /* Modularization */ 924 + 925 + module_init(vt8623fb_init); 926 + module_exit(vt8623fb_cleanup);