0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/module.h>
0016 #include <linux/kernel.h>
0017 #include <linux/errno.h>
0018 #include <linux/string.h>
0019 #include <linux/mm.h>
0020 #include <linux/tty.h>
0021 #include <linux/delay.h>
0022 #include <linux/fb.h>
0023 #include <linux/svga.h>
0024 #include <linux/init.h>
0025 #include <linux/pci.h>
0026 #include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
0027 #include <video/vga.h>
0028
0029 struct vt8623fb_info {
0030 char __iomem *mmio_base;
0031 int wc_cookie;
0032 struct vgastate state;
0033 struct mutex open_lock;
0034 unsigned int ref_count;
0035 u32 pseudo_palette[16];
0036 };
0037
0038
0039
0040
0041
0042 static const struct svga_fb_format vt8623fb_formats[] = {
0043 { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
0044 FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8, FB_VISUAL_PSEUDOCOLOR, 16, 16},
0045 { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
0046 FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 16},
0047 { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1,
0048 FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 16, 16},
0049 { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
0050 FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8},
0051
0052
0053 {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0,
0054 FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
0055 {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
0056 FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2},
0057 SVGA_FORMAT_END
0058 };
0059
0060 static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3,
0061 60000, 300000, 14318};
0062
0063
0064
0065 static const struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
0066 static const struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
0067 static const struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
0068 static const struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
0069 static const struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
0070 static const struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
0071
0072 static const struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
0073 static const struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
0074 static const struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
0075 static const struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
0076 static const struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
0077 static const struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
0078
0079 static const struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
0080 static const 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};
0081 static const struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
0082 static const struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
0083
0084 static const struct svga_timing_regs vt8623_timing_regs = {
0085 vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs,
0086 vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs,
0087 vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs,
0088 vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs,
0089 };
0090
0091
0092
0093
0094
0095
0096
0097 static char *mode_option = "640x480-8@60";
0098 static int mtrr = 1;
0099
0100 MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>");
0101 MODULE_LICENSE("GPL");
0102 MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]");
0103
0104 module_param(mode_option, charp, 0644);
0105 MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
0106 module_param_named(mode, mode_option, charp, 0);
0107 MODULE_PARM_DESC(mode, "Default video mode e.g. '648x480-8@60' (deprecated)");
0108 module_param(mtrr, int, 0444);
0109 MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
0110
0111
0112
0113
0114 static void vt8623fb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
0115 {
0116 struct vt8623fb_info *par = info->par;
0117
0118 svga_tilecursor(par->state.vgabase, info, cursor);
0119 }
0120
0121 static struct fb_tile_ops vt8623fb_tile_ops = {
0122 .fb_settile = svga_settile,
0123 .fb_tilecopy = svga_tilecopy,
0124 .fb_tilefill = svga_tilefill,
0125 .fb_tileblit = svga_tileblit,
0126 .fb_tilecursor = vt8623fb_tilecursor,
0127 .fb_get_tilemax = svga_get_tilemax,
0128 };
0129
0130
0131
0132
0133
0134
0135 static inline u32 expand_color(u32 c)
0136 {
0137 return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
0138 }
0139
0140
0141 static void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
0142 {
0143 u32 fg = expand_color(image->fg_color);
0144 u32 bg = expand_color(image->bg_color);
0145 const u8 *src1, *src;
0146 u8 __iomem *dst1;
0147 u32 __iomem *dst;
0148 u32 val;
0149 int x, y;
0150
0151 src1 = image->data;
0152 dst1 = info->screen_base + (image->dy * info->fix.line_length)
0153 + ((image->dx / 8) * 4);
0154
0155 for (y = 0; y < image->height; y++) {
0156 src = src1;
0157 dst = (u32 __iomem *) dst1;
0158 for (x = 0; x < image->width; x += 8) {
0159 val = *(src++) * 0x01010101;
0160 val = (val & fg) | (~val & bg);
0161 fb_writel(val, dst++);
0162 }
0163 src1 += image->width / 8;
0164 dst1 += info->fix.line_length;
0165 }
0166 }
0167
0168
0169 static void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0170 {
0171 u32 fg = expand_color(rect->color);
0172 u8 __iomem *dst1;
0173 u32 __iomem *dst;
0174 int x, y;
0175
0176 dst1 = info->screen_base + (rect->dy * info->fix.line_length)
0177 + ((rect->dx / 8) * 4);
0178
0179 for (y = 0; y < rect->height; y++) {
0180 dst = (u32 __iomem *) dst1;
0181 for (x = 0; x < rect->width; x += 8) {
0182 fb_writel(fg, dst++);
0183 }
0184 dst1 += info->fix.line_length;
0185 }
0186 }
0187
0188
0189
0190 static inline u32 expand_pixel(u32 c)
0191 {
0192 return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) |
0193 ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF;
0194 }
0195
0196
0197 static void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
0198 {
0199 u32 fg = image->fg_color * 0x11111111;
0200 u32 bg = image->bg_color * 0x11111111;
0201 const u8 *src1, *src;
0202 u8 __iomem *dst1;
0203 u32 __iomem *dst;
0204 u32 val;
0205 int x, y;
0206
0207 src1 = image->data;
0208 dst1 = info->screen_base + (image->dy * info->fix.line_length)
0209 + ((image->dx / 8) * 4);
0210
0211 for (y = 0; y < image->height; y++) {
0212 src = src1;
0213 dst = (u32 __iomem *) dst1;
0214 for (x = 0; x < image->width; x += 8) {
0215 val = expand_pixel(*(src++));
0216 val = (val & fg) | (~val & bg);
0217 fb_writel(val, dst++);
0218 }
0219 src1 += image->width / 8;
0220 dst1 += info->fix.line_length;
0221 }
0222 }
0223
0224 static void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image)
0225 {
0226 if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
0227 && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
0228 if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
0229 vt8623fb_iplan_imageblit(info, image);
0230 else
0231 vt8623fb_cfb4_imageblit(info, image);
0232 } else
0233 cfb_imageblit(info, image);
0234 }
0235
0236 static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0237 {
0238 if ((info->var.bits_per_pixel == 4)
0239 && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
0240 && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
0241 vt8623fb_iplan_fillrect(info, rect);
0242 else
0243 cfb_fillrect(info, rect);
0244 }
0245
0246
0247
0248
0249
0250 static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock)
0251 {
0252 struct vt8623fb_info *par = info->par;
0253 u16 m, n, r;
0254 u8 regval;
0255 int rv;
0256
0257 rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
0258 if (rv < 0) {
0259 fb_err(info, "cannot set requested pixclock, keeping old value\n");
0260 return;
0261 }
0262
0263
0264 regval = vga_r(par->state.vgabase, VGA_MIS_R);
0265 vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
0266
0267
0268 vga_wseq(par->state.vgabase, 0x46, (n | (r << 6)));
0269 vga_wseq(par->state.vgabase, 0x47, m);
0270
0271 udelay(1000);
0272
0273
0274 svga_wseq_mask(par->state.vgabase, 0x40, 0x02, 0x02);
0275 svga_wseq_mask(par->state.vgabase, 0x40, 0x00, 0x02);
0276 }
0277
0278
0279 static int vt8623fb_open(struct fb_info *info, int user)
0280 {
0281 struct vt8623fb_info *par = info->par;
0282
0283 mutex_lock(&(par->open_lock));
0284 if (par->ref_count == 0) {
0285 void __iomem *vgabase = par->state.vgabase;
0286
0287 memset(&(par->state), 0, sizeof(struct vgastate));
0288 par->state.vgabase = vgabase;
0289 par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
0290 par->state.num_crtc = 0xA2;
0291 par->state.num_seq = 0x50;
0292 save_vga(&(par->state));
0293 }
0294
0295 par->ref_count++;
0296 mutex_unlock(&(par->open_lock));
0297
0298 return 0;
0299 }
0300
0301 static int vt8623fb_release(struct fb_info *info, int user)
0302 {
0303 struct vt8623fb_info *par = info->par;
0304
0305 mutex_lock(&(par->open_lock));
0306 if (par->ref_count == 0) {
0307 mutex_unlock(&(par->open_lock));
0308 return -EINVAL;
0309 }
0310
0311 if (par->ref_count == 1)
0312 restore_vga(&(par->state));
0313
0314 par->ref_count--;
0315 mutex_unlock(&(par->open_lock));
0316
0317 return 0;
0318 }
0319
0320 static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
0321 {
0322 int rv, mem, step;
0323
0324 if (!var->pixclock)
0325 return -EINVAL;
0326
0327
0328 rv = svga_match_format (vt8623fb_formats, var, NULL);
0329 if (rv < 0)
0330 {
0331 fb_err(info, "unsupported mode requested\n");
0332 return rv;
0333 }
0334
0335
0336 if (var->xres > var->xres_virtual)
0337 var->xres_virtual = var->xres;
0338
0339 if (var->yres > var->yres_virtual)
0340 var->yres_virtual = var->yres;
0341
0342
0343 step = vt8623fb_formats[rv].xresstep - 1;
0344 var->xres_virtual = (var->xres_virtual+step) & ~step;
0345
0346
0347 mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
0348 if (mem > info->screen_size)
0349 {
0350 fb_err(info, "not enough framebuffer memory (%d kB requested, %d kB available)\n",
0351 mem >> 10, (unsigned int) (info->screen_size >> 10));
0352 return -EINVAL;
0353 }
0354
0355
0356 if ((var->bits_per_pixel == 0) && (mem > (256*1024)))
0357 {
0358 fb_err(info, "text framebuffer size too large (%d kB requested, 256 kB possible)\n",
0359 mem >> 10);
0360 return -EINVAL;
0361 }
0362
0363 rv = svga_check_timings (&vt8623_timing_regs, var, info->node);
0364 if (rv < 0)
0365 {
0366 fb_err(info, "invalid timings requested\n");
0367 return rv;
0368 }
0369
0370
0371 if (var->vmode & FB_VMODE_INTERLACED)
0372 return -EINVAL;
0373
0374 return 0;
0375 }
0376
0377
0378 static int vt8623fb_set_par(struct fb_info *info)
0379 {
0380 u32 mode, offset_value, fetch_value, screen_size;
0381 struct vt8623fb_info *par = info->par;
0382 u32 bpp = info->var.bits_per_pixel;
0383
0384 if (bpp != 0) {
0385 info->fix.ypanstep = 1;
0386 info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
0387
0388 info->flags &= ~FBINFO_MISC_TILEBLITTING;
0389 info->tileops = NULL;
0390
0391
0392 info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
0393 info->pixmap.blit_y = ~(u32)0;
0394
0395 offset_value = (info->var.xres_virtual * bpp) / 64;
0396 fetch_value = ((info->var.xres * bpp) / 128) + 4;
0397
0398 if (bpp == 4)
0399 fetch_value = (info->var.xres / 8) + 8;
0400
0401 screen_size = info->var.yres_virtual * info->fix.line_length;
0402 } else {
0403 info->fix.ypanstep = 16;
0404 info->fix.line_length = 0;
0405
0406 info->flags |= FBINFO_MISC_TILEBLITTING;
0407 info->tileops = &vt8623fb_tile_ops;
0408
0409
0410 info->pixmap.blit_x = 1 << (8 - 1);
0411 info->pixmap.blit_y = 1 << (16 - 1);
0412
0413 offset_value = info->var.xres_virtual / 16;
0414 fetch_value = (info->var.xres / 8) + 8;
0415 screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
0416 }
0417
0418 info->var.xoffset = 0;
0419 info->var.yoffset = 0;
0420 info->var.activate = FB_ACTIVATE_NOW;
0421
0422
0423 svga_wseq_mask(par->state.vgabase, 0x10, 0x01, 0x01);
0424 svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80);
0425 svga_wcrt_mask(par->state.vgabase, 0x47, 0x00, 0x01);
0426
0427
0428 svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
0429 svga_wcrt_mask(par->state.vgabase, 0x36, 0x30, 0x30);
0430 svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80);
0431
0432
0433 svga_set_default_gfx_regs(par->state.vgabase);
0434 svga_set_default_atc_regs(par->state.vgabase);
0435 svga_set_default_seq_regs(par->state.vgabase);
0436 svga_set_default_crt_regs(par->state.vgabase);
0437 svga_wcrt_multi(par->state.vgabase, vt8623_line_compare_regs, 0xFFFFFFFF);
0438 svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, 0);
0439
0440 svga_wcrt_multi(par->state.vgabase, vt8623_offset_regs, offset_value);
0441 svga_wseq_multi(par->state.vgabase, vt8623_fetch_count_regs, fetch_value);
0442
0443
0444 svga_wcrt_mask(par->state.vgabase, 0x03, 0x00, 0x60);
0445 svga_wcrt_mask(par->state.vgabase, 0x05, 0x00, 0x60);
0446
0447 if (info->var.vmode & FB_VMODE_DOUBLE)
0448 svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80);
0449 else
0450 svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80);
0451
0452 svga_wseq_mask(par->state.vgabase, 0x1E, 0xF0, 0xF0);
0453 svga_wseq_mask(par->state.vgabase, 0x2A, 0x0F, 0x0F);
0454 svga_wseq_mask(par->state.vgabase, 0x16, 0x08, 0xBF);
0455 vga_wseq(par->state.vgabase, 0x17, 0x1F);
0456 vga_wseq(par->state.vgabase, 0x18, 0x4E);
0457 svga_wseq_mask(par->state.vgabase, 0x1A, 0x08, 0x08);
0458
0459 vga_wcrt(par->state.vgabase, 0x32, 0x00);
0460 vga_wcrt(par->state.vgabase, 0x34, 0x00);
0461 vga_wcrt(par->state.vgabase, 0x6A, 0x80);
0462 vga_wcrt(par->state.vgabase, 0x6A, 0xC0);
0463
0464 vga_wgfx(par->state.vgabase, 0x20, 0x00);
0465 vga_wgfx(par->state.vgabase, 0x21, 0x00);
0466 vga_wgfx(par->state.vgabase, 0x22, 0x00);
0467
0468
0469 mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix));
0470 switch (mode) {
0471 case 0:
0472 fb_dbg(info, "text mode\n");
0473 svga_set_textmode_vga_regs(par->state.vgabase);
0474 svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE);
0475 svga_wcrt_mask(par->state.vgabase, 0x11, 0x60, 0x70);
0476 break;
0477 case 1:
0478 fb_dbg(info, "4 bit pseudocolor\n");
0479 vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
0480 svga_wseq_mask(par->state.vgabase, 0x15, 0x20, 0xFE);
0481 svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70);
0482 break;
0483 case 2:
0484 fb_dbg(info, "4 bit pseudocolor, planar\n");
0485 svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE);
0486 svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70);
0487 break;
0488 case 3:
0489 fb_dbg(info, "8 bit pseudocolor\n");
0490 svga_wseq_mask(par->state.vgabase, 0x15, 0x22, 0xFE);
0491 break;
0492 case 4:
0493 fb_dbg(info, "5/6/5 truecolor\n");
0494 svga_wseq_mask(par->state.vgabase, 0x15, 0xB6, 0xFE);
0495 break;
0496 case 5:
0497 fb_dbg(info, "8/8/8 truecolor\n");
0498 svga_wseq_mask(par->state.vgabase, 0x15, 0xAE, 0xFE);
0499 break;
0500 default:
0501 printk(KERN_ERR "vt8623fb: unsupported mode - bug\n");
0502 return (-EINVAL);
0503 }
0504
0505 vt8623_set_pixclock(info, info->var.pixclock);
0506 svga_set_timings(par->state.vgabase, &vt8623_timing_regs, &(info->var), 1, 1,
0507 (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1,
0508 1, info->node);
0509
0510 if (screen_size > info->screen_size)
0511 screen_size = info->screen_size;
0512 memset_io(info->screen_base, 0x00, screen_size);
0513
0514
0515 svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80);
0516 svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30);
0517 svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
0518
0519 return 0;
0520 }
0521
0522
0523 static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0524 u_int transp, struct fb_info *fb)
0525 {
0526 switch (fb->var.bits_per_pixel) {
0527 case 0:
0528 case 4:
0529 if (regno >= 16)
0530 return -EINVAL;
0531
0532 outb(0x0F, VGA_PEL_MSK);
0533 outb(regno, VGA_PEL_IW);
0534 outb(red >> 10, VGA_PEL_D);
0535 outb(green >> 10, VGA_PEL_D);
0536 outb(blue >> 10, VGA_PEL_D);
0537 break;
0538 case 8:
0539 if (regno >= 256)
0540 return -EINVAL;
0541
0542 outb(0xFF, VGA_PEL_MSK);
0543 outb(regno, VGA_PEL_IW);
0544 outb(red >> 10, VGA_PEL_D);
0545 outb(green >> 10, VGA_PEL_D);
0546 outb(blue >> 10, VGA_PEL_D);
0547 break;
0548 case 16:
0549 if (regno >= 16)
0550 return 0;
0551
0552 if (fb->var.green.length == 5)
0553 ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
0554 ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
0555 else if (fb->var.green.length == 6)
0556 ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
0557 ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
0558 else
0559 return -EINVAL;
0560 break;
0561 case 24:
0562 case 32:
0563 if (regno >= 16)
0564 return 0;
0565
0566
0567 ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
0568 (green & 0xFF00) | ((blue & 0xFF00) >> 8);
0569 break;
0570 default:
0571 return -EINVAL;
0572 }
0573
0574 return 0;
0575 }
0576
0577
0578 static int vt8623fb_blank(int blank_mode, struct fb_info *info)
0579 {
0580 struct vt8623fb_info *par = info->par;
0581
0582 switch (blank_mode) {
0583 case FB_BLANK_UNBLANK:
0584 fb_dbg(info, "unblank\n");
0585 svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30);
0586 svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
0587 break;
0588 case FB_BLANK_NORMAL:
0589 fb_dbg(info, "blank\n");
0590 svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30);
0591 svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
0592 break;
0593 case FB_BLANK_HSYNC_SUSPEND:
0594 fb_dbg(info, "DPMS standby (hsync off)\n");
0595 svga_wcrt_mask(par->state.vgabase, 0x36, 0x10, 0x30);
0596 svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
0597 break;
0598 case FB_BLANK_VSYNC_SUSPEND:
0599 fb_dbg(info, "DPMS suspend (vsync off)\n");
0600 svga_wcrt_mask(par->state.vgabase, 0x36, 0x20, 0x30);
0601 svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
0602 break;
0603 case FB_BLANK_POWERDOWN:
0604 fb_dbg(info, "DPMS off (no sync)\n");
0605 svga_wcrt_mask(par->state.vgabase, 0x36, 0x30, 0x30);
0606 svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
0607 break;
0608 }
0609
0610 return 0;
0611 }
0612
0613
0614 static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
0615 {
0616 struct vt8623fb_info *par = info->par;
0617 unsigned int offset;
0618
0619
0620 if (info->var.bits_per_pixel == 0) {
0621 offset = (var->yoffset / 16) * info->var.xres_virtual
0622 + var->xoffset;
0623 offset = offset >> 3;
0624 } else {
0625 offset = (var->yoffset * info->fix.line_length) +
0626 (var->xoffset * info->var.bits_per_pixel / 8);
0627 offset = offset >> ((info->var.bits_per_pixel == 4) ? 2 : 1);
0628 }
0629
0630
0631 svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, offset);
0632
0633 return 0;
0634 }
0635
0636
0637
0638
0639
0640
0641
0642 static const struct fb_ops vt8623fb_ops = {
0643 .owner = THIS_MODULE,
0644 .fb_open = vt8623fb_open,
0645 .fb_release = vt8623fb_release,
0646 .fb_check_var = vt8623fb_check_var,
0647 .fb_set_par = vt8623fb_set_par,
0648 .fb_setcolreg = vt8623fb_setcolreg,
0649 .fb_blank = vt8623fb_blank,
0650 .fb_pan_display = vt8623fb_pan_display,
0651 .fb_fillrect = vt8623fb_fillrect,
0652 .fb_copyarea = cfb_copyarea,
0653 .fb_imageblit = vt8623fb_imageblit,
0654 .fb_get_caps = svga_get_caps,
0655 };
0656
0657
0658
0659
0660 static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
0661 {
0662 struct pci_bus_region bus_reg;
0663 struct resource vga_res;
0664 struct fb_info *info;
0665 struct vt8623fb_info *par;
0666 unsigned int memsize1, memsize2;
0667 int rc;
0668
0669
0670 if (! svga_primary_device(dev)) {
0671 dev_info(&(dev->dev), "ignoring secondary device\n");
0672 return -ENODEV;
0673 }
0674
0675
0676 info = framebuffer_alloc(sizeof(struct vt8623fb_info), &(dev->dev));
0677 if (!info)
0678 return -ENOMEM;
0679
0680 par = info->par;
0681 mutex_init(&par->open_lock);
0682
0683 info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
0684 info->fbops = &vt8623fb_ops;
0685
0686
0687
0688 rc = pci_enable_device(dev);
0689 if (rc < 0) {
0690 dev_err(info->device, "cannot enable PCI device\n");
0691 goto err_enable_device;
0692 }
0693
0694 rc = pci_request_regions(dev, "vt8623fb");
0695 if (rc < 0) {
0696 dev_err(info->device, "cannot reserve framebuffer region\n");
0697 goto err_request_regions;
0698 }
0699
0700 info->fix.smem_start = pci_resource_start(dev, 0);
0701 info->fix.smem_len = pci_resource_len(dev, 0);
0702 info->fix.mmio_start = pci_resource_start(dev, 1);
0703 info->fix.mmio_len = pci_resource_len(dev, 1);
0704
0705
0706 info->screen_base = pci_iomap_wc(dev, 0, 0);
0707 if (! info->screen_base) {
0708 rc = -ENOMEM;
0709 dev_err(info->device, "iomap for framebuffer failed\n");
0710 goto err_iomap_1;
0711 }
0712
0713 par->mmio_base = pci_iomap(dev, 1, 0);
0714 if (! par->mmio_base) {
0715 rc = -ENOMEM;
0716 dev_err(info->device, "iomap for MMIO failed\n");
0717 goto err_iomap_2;
0718 }
0719
0720 bus_reg.start = 0;
0721 bus_reg.end = 64 * 1024;
0722
0723 vga_res.flags = IORESOURCE_IO;
0724
0725 pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
0726
0727 par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
0728
0729
0730 memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1;
0731 memsize2 = vga_rseq(par->state.vgabase, 0x39) << 2;
0732
0733 if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2))
0734 info->screen_size = memsize1 << 20;
0735 else {
0736 dev_err(info->device, "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2);
0737 info->screen_size = 16 << 20;
0738 }
0739
0740 info->fix.smem_len = info->screen_size;
0741 strcpy(info->fix.id, "VIA VT8623");
0742 info->fix.type = FB_TYPE_PACKED_PIXELS;
0743 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
0744 info->fix.ypanstep = 0;
0745 info->fix.accel = FB_ACCEL_NONE;
0746 info->pseudo_palette = (void*)par->pseudo_palette;
0747
0748
0749
0750 kernel_param_lock(THIS_MODULE);
0751 rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
0752 kernel_param_unlock(THIS_MODULE);
0753 if (! ((rc == 1) || (rc == 2))) {
0754 rc = -EINVAL;
0755 dev_err(info->device, "mode %s not found\n", mode_option);
0756 goto err_find_mode;
0757 }
0758
0759 rc = fb_alloc_cmap(&info->cmap, 256, 0);
0760 if (rc < 0) {
0761 dev_err(info->device, "cannot allocate colormap\n");
0762 goto err_alloc_cmap;
0763 }
0764
0765 rc = register_framebuffer(info);
0766 if (rc < 0) {
0767 dev_err(info->device, "cannot register framebuffer\n");
0768 goto err_reg_fb;
0769 }
0770
0771 fb_info(info, "%s on %s, %d MB RAM\n",
0772 info->fix.id, pci_name(dev), info->fix.smem_len >> 20);
0773
0774
0775 pci_set_drvdata(dev, info);
0776
0777 if (mtrr)
0778 par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,
0779 info->fix.smem_len);
0780
0781 return 0;
0782
0783
0784 err_reg_fb:
0785 fb_dealloc_cmap(&info->cmap);
0786 err_alloc_cmap:
0787 err_find_mode:
0788 pci_iounmap(dev, par->mmio_base);
0789 err_iomap_2:
0790 pci_iounmap(dev, info->screen_base);
0791 err_iomap_1:
0792 pci_release_regions(dev);
0793 err_request_regions:
0794
0795 err_enable_device:
0796 framebuffer_release(info);
0797 return rc;
0798 }
0799
0800
0801
0802 static void vt8623_pci_remove(struct pci_dev *dev)
0803 {
0804 struct fb_info *info = pci_get_drvdata(dev);
0805
0806 if (info) {
0807 struct vt8623fb_info *par = info->par;
0808
0809 arch_phys_wc_del(par->wc_cookie);
0810 unregister_framebuffer(info);
0811 fb_dealloc_cmap(&info->cmap);
0812
0813 pci_iounmap(dev, info->screen_base);
0814 pci_iounmap(dev, par->mmio_base);
0815 pci_release_regions(dev);
0816
0817
0818 framebuffer_release(info);
0819 }
0820 }
0821
0822
0823
0824
0825 static int __maybe_unused vt8623_pci_suspend(struct device *dev)
0826 {
0827 struct fb_info *info = dev_get_drvdata(dev);
0828 struct vt8623fb_info *par = info->par;
0829
0830 dev_info(info->device, "suspend\n");
0831
0832 console_lock();
0833 mutex_lock(&(par->open_lock));
0834
0835 if (par->ref_count == 0) {
0836 mutex_unlock(&(par->open_lock));
0837 console_unlock();
0838 return 0;
0839 }
0840
0841 fb_set_suspend(info, 1);
0842
0843 mutex_unlock(&(par->open_lock));
0844 console_unlock();
0845
0846 return 0;
0847 }
0848
0849
0850
0851
0852 static int __maybe_unused vt8623_pci_resume(struct device *dev)
0853 {
0854 struct fb_info *info = dev_get_drvdata(dev);
0855 struct vt8623fb_info *par = info->par;
0856
0857 dev_info(info->device, "resume\n");
0858
0859 console_lock();
0860 mutex_lock(&(par->open_lock));
0861
0862 if (par->ref_count == 0)
0863 goto fail;
0864
0865 vt8623fb_set_par(info);
0866 fb_set_suspend(info, 0);
0867
0868 fail:
0869 mutex_unlock(&(par->open_lock));
0870 console_unlock();
0871
0872 return 0;
0873 }
0874
0875 static const struct dev_pm_ops vt8623_pci_pm_ops = {
0876 #ifdef CONFIG_PM_SLEEP
0877 .suspend = vt8623_pci_suspend,
0878 .resume = vt8623_pci_resume,
0879 .freeze = NULL,
0880 .thaw = vt8623_pci_resume,
0881 .poweroff = vt8623_pci_suspend,
0882 .restore = vt8623_pci_resume,
0883 #endif
0884 };
0885
0886
0887
0888 static const struct pci_device_id vt8623_devices[] = {
0889 {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},
0890 {0, 0, 0, 0, 0, 0, 0}
0891 };
0892
0893 MODULE_DEVICE_TABLE(pci, vt8623_devices);
0894
0895 static struct pci_driver vt8623fb_pci_driver = {
0896 .name = "vt8623fb",
0897 .id_table = vt8623_devices,
0898 .probe = vt8623_pci_probe,
0899 .remove = vt8623_pci_remove,
0900 .driver.pm = &vt8623_pci_pm_ops,
0901 };
0902
0903
0904
0905 static void __exit vt8623fb_cleanup(void)
0906 {
0907 pr_debug("vt8623fb: cleaning up\n");
0908 pci_unregister_driver(&vt8623fb_pci_driver);
0909 }
0910
0911
0912
0913 static int __init vt8623fb_init(void)
0914 {
0915
0916 #ifndef MODULE
0917 char *option = NULL;
0918
0919 if (fb_get_options("vt8623fb", &option))
0920 return -ENODEV;
0921
0922 if (option && *option)
0923 mode_option = option;
0924 #endif
0925
0926 pr_debug("vt8623fb: initializing\n");
0927 return pci_register_driver(&vt8623fb_pci_driver);
0928 }
0929
0930
0931
0932
0933
0934 module_init(vt8623fb_init);
0935 module_exit(vt8623fb_cleanup);