30 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/errno.h>
34 #include <linux/string.h>
36 #include <linux/slab.h>
40 #include <linux/pci.h>
48 #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
49 #error "The endianness of the target host has not been defined."
52 #if !defined(CONFIG_PCI)
53 #error "Only generic PCI cards supported."
56 #undef PM2FB_MASTER_DEBUG
57 #ifdef PM2FB_MASTER_DEBUG
58 #define DPRINTK(a, b...) \
59 printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b)
61 #define DPRINTK(a, b...)
64 #define PM2_PIXMAP_SIZE (1600 * 4)
69 static int hwcursor = 1;
191 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
192 #define WAIT_FIFO(p, a)
204 #define PACKPP(p0, p1, p2) (((p2) << 6) | ((p1) << 3) | (p0))
205 static const struct {
227 static u32 partprod(
u32 xres)
231 for (i = 0; pp_table[
i].width && pp_table[
i].width != xres; i++)
233 if (pp_table[i].
width == 0)
234 DPRINTK(
"invalid width %u\n", xres);
235 return pp_table[
i].pp;
255 static void pm2_mnp(
u32 clk,
unsigned char *mm,
unsigned char *
nn,
266 for (n = 2; n < 15; n++) {
267 for (m = 2;
m; m++) {
269 if (f >= 150000 && f <= 300000) {
270 for (p = 0; p < 5; p++, f >>= 1) {
271 curr = (clk >
f) ? clk - f : f - clk;
284 static void pm2v_mnp(
u32 clk,
unsigned char *mm,
unsigned char *nn,
294 for (m = 1; m < 128; m++) {
295 for (n = 2 * m + 1;
n; n++) {
296 for (p = 0; p < 2; p++) {
298 if (clk > f - delta && clk < f + delta) {
299 delta = (clk >
f) ? clk - f : f - clk;
309 static void clear_palette(
struct pm2fb_par *p)
324 static void reset_card(
struct pm2fb_par *p)
333 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
334 DPRINTK(
"FIFO disconnect enabled\n");
347 static void reset_config(
struct pm2fb_par *p)
412 #ifdef __LITTLE_ENDIAN
438 static void set_color(
struct pm2fb_par *p,
unsigned char regno,
439 unsigned char r,
unsigned char g,
unsigned char b)
451 static void set_memclock(
struct pm2fb_par *par,
u32 clk)
454 unsigned char m,
n,
p;
458 pm2v_mnp(clk/2, &m, &n, &p);
467 for (i = 256;
i; i--)
473 pm2_mnp(clk, &m, &n, &p);
481 for (i = 256;
i; i--)
488 static void set_pixclock(
struct pm2fb_par *par,
u32 clk)
491 unsigned char m,
n,
p;
495 pm2_mnp(clk, &m, &n, &p);
503 for (i = 256;
i; i--)
508 pm2v_mnp(clk/2, &m, &n, &p);
524 DPRINTK(
"video = 0x%x\n", video);
579 DPRINTK(
"virtual x resolution != "
580 "physical x resolution not supported\n");
585 DPRINTK(
"virtual y resolution < "
586 "physical y resolution not possible\n");
596 DPRINTK(
"xoffset not supported\n");
601 DPRINTK(
"interlace not supported\n");
608 if (var->
xres < 320 || var->
xres > 1600) {
613 if (var->
yres < 200 || var->
yres > 1200) {
619 DPRINTK(
"no memory for screen (%ux%ux%u)\n",
625 DPRINTK(
"pixclock too high (%ldKHz)\n",
635 var->
green.length = 8;
636 var->
blue.length = 8;
639 var->
red.offset = 11;
641 var->
green.offset = 5;
642 var->
green.length = 6;
643 var->
blue.offset = 0;
644 var->
blue.length = 5;
649 var->
red.offset = 16;
650 var->
green.offset = 8;
651 var->
blue.offset = 0;
653 var->
green.length = 8;
654 var->
blue.length = 8;
659 var->
blue.offset = 16;
661 var->
red.offset = 16;
662 var->
blue.offset = 0;
664 var->
green.offset = 8;
666 var->
green.length = 8;
667 var->
blue.length = 8;
675 DPRINTK(
"Checking graphics mode at %dx%d depth %d\n",
687 static int pm2fb_set_par(
struct fb_info *info)
693 u32 depth = (info->
var.bits_per_pixel + 7) & ~7;
694 u32 hsstart, hsend, hbend, htotal;
695 u32 vsstart, vsend, vbend, vtotal;
704 u32 xres = (info->
var.xres + 31) & ~31;
713 depth = (depth > 32) ? 32 : depth;
718 DPRINTK(
"pixclock too high (%uKHz)\n", pixclock);
722 hsstart = to3264(info->
var.right_margin, depth, data64);
723 hsend = hsstart + to3264(info->
var.hsync_len, depth, data64);
724 hbend = hsend + to3264(info->
var.left_margin, depth, data64);
725 htotal = to3264(xres, depth, data64) + hbend - 1;
726 vsstart = (info->
var.lower_margin)
727 ? info->
var.lower_margin - 1
729 vsend = info->
var.lower_margin + info->
var.vsync_len - 1;
730 vbend = info->
var.lower_margin + info->
var.vsync_len +
731 info->
var.upper_margin;
732 vtotal = info->
var.yres + vbend - 1;
733 stride = to3264(width, depth, 1);
734 base = to3264(info->
var.yoffset * xres + info->
var.xoffset, depth, 1);
740 DPRINTK(
"ignoring +hsync, using -hsync.\n");
749 DPRINTK(
"ignoring +vsync, using -vsync.\n");
757 DPRINTK(
"interlaced not supported\n");
768 info->
fix.line_length = info->
var.xres * depth / 8;
769 info->
cmap.len = 256;
779 set_aperture(par, depth);
850 set_pixclock(par, pixclock);
851 DPRINTK(
"Setting graphics mode at %dx%d depth %d\n",
852 info->
var.xres, info->
var.yres, info->
var.bits_per_pixel);
871 static int pm2fb_setcolreg(
unsigned regno,
unsigned red,
unsigned green,
877 if (regno >= info->
cmap.len)
885 if (info->
var.grayscale)
886 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
911 #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16)
912 switch (info->
fix.visual) {
938 v = (red << info->
var.red.offset) |
939 (green << info->
var.green.offset) |
940 (blue << info->
var.blue.offset) |
941 (transp << info->
var.transp.offset);
943 switch (info->
var.bits_per_pixel) {
954 set_color(par, regno, red, green, blue);
976 u32 depth = (info->
var.bits_per_pixel + 7) & ~7;
977 u32 xres = (info->
var.xres + 31) & ~31;
979 depth = (depth > 32) ? 32 : depth;
1002 static int pm2fb_blank(
int blank_mode,
struct fb_info *info)
1007 DPRINTK(
"blank_mode %d\n", blank_mode);
1009 switch (blank_mode) {
1035 static int pm2fb_sync(
struct fb_info *info)
1050 static void pm2fb_fillrect(
struct fb_info *info,
1067 vxres = info->
var.xres_virtual;
1068 vyres = info->
var.yres_virtual;
1072 if (!modded.width || !modded.height ||
1073 modded.dx >= vxres || modded.dy >= vyres)
1076 if (modded.dx + modded.width > vxres)
1077 modded.width = vxres - modded.dx;
1078 if (modded.dy + modded.height > vyres)
1079 modded.height = vyres - modded.dy;
1081 if (info->
var.bits_per_pixel == 8)
1082 color |= color << 8;
1083 if (info->
var.bits_per_pixel <= 16)
1084 color |= color << 16;
1090 if (info->
var.bits_per_pixel != 24) {
1108 static void pm2fb_copyarea(
struct fb_info *info,
1124 vxres = info->
var.xres_virtual;
1125 vyres = info->
var.yres_virtual;
1127 if (!modded.width || !modded.height ||
1128 modded.sx >= vxres || modded.sy >= vyres ||
1129 modded.dx >= vxres || modded.dy >= vyres)
1132 if (modded.sx + modded.width > vxres)
1133 modded.width = vxres - modded.sx;
1134 if (modded.dx + modded.width > vxres)
1135 modded.width = vxres - modded.dx;
1136 if (modded.sy + modded.height > vyres)
1137 modded.height = vyres - modded.sy;
1138 if (modded.dy + modded.height > vyres)
1139 modded.height = vyres - modded.dy;
1145 ((modded.sy - modded.dy) & 0xfff) << 16 |
1146 ((modded.sx - modded.dx) & 0xfff));
1161 u32 xres = (info->
var.xres + 31) & ~31;
1162 int raster_mode = 1;
1164 #ifdef __LITTLE_ENDIAN
1165 raster_mode |= 3 << 7;
1174 switch (info->
fix.visual) {
1185 if (info->
var.bits_per_pixel == 8) {
1189 if (info->
var.bits_per_pixel <= 16) {
1197 ((image->
dy & 0xfff) << 16) | (image->
dx & 0x0fff));
1199 (((image->
dy + image->
height) & 0x0fff) << 16) |
1200 ((image->
dx + image->
width) & 0x0fff));
1205 ((image->
dy & 0xfff) << 16) | (image->
dx & 0x0fff));
1207 ((image->
height & 0x0fff) << 16) |
1208 ((image->
width) & 0x0fff));
1209 if (info->
var.bits_per_pixel == 24) {
1241 int width = ((image->
width + 7) >> 3)
1242 + info->
pixmap.scan_align - 1;
1244 WAIT_FIFO(par, width);
1259 static const u8 cursor_bits_lookup[16] = {
1260 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
1261 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
1268 int x = cursor->
image.dx - info->
var.xoffset;
1269 int y = cursor->
image.dy - info->
var.yoffset;
1293 cursor->
hot.x & 0x3f);
1295 cursor->
hot.y & 0x3f);
1299 u32 fg_idx = cursor->
image.fg_color;
1300 u32 bg_idx = cursor->
image.bg_color;
1306 cmap.
red[bg_idx] >> 8 );
1308 cmap.
green[bg_idx] >> 8 );
1310 cmap.
blue[bg_idx] >> 8 );
1313 cmap.
red[fg_idx] >> 8 );
1315 cmap.
green[fg_idx] >> 8 );
1317 cmap.
blue[fg_idx] >> 8 );
1327 for (i = 0; i < cursor->
image.height; i++) {
1328 int j = (cursor->
image.width + 7) >> 3;
1333 for (; j > 0; j--) {
1339 pm2v_RDAC_WR(par, pos++,
1340 cursor_bits_lookup[data >> 4] |
1341 (cursor_bits_lookup[*mask >> 4] << 1));
1343 pm2v_RDAC_WR(par, pos++,
1344 cursor_bits_lookup[data & 0xf] |
1345 (cursor_bits_lookup[*mask & 0xf] << 1));
1349 for (; k > 0; k--) {
1350 pm2v_RDAC_WR(par, pos++, 0);
1351 pm2v_RDAC_WR(par, pos++, 0);
1357 pm2v_RDAC_WR(par, pos++, 0);
1374 if (cursor->
image.width > 64 ||
1375 cursor->
image.height > 64 ||
1376 cursor->
image.depth > 1)
1380 return pm2vfb_cursor(info, cursor);
1397 int x = cursor->
image.dx - info->
var.xoffset + 63;
1398 int y = cursor->
image.dy - info->
var.yoffset + 63;
1408 u32 fg_idx = cursor->
image.fg_color;
1409 u32 bg_idx = cursor->
image.bg_color;
1414 info->
cmap.red[bg_idx] >> 8);
1416 info->
cmap.green[bg_idx] >> 8);
1418 info->
cmap.blue[bg_idx] >> 8);
1421 info->
cmap.red[fg_idx] >> 8);
1423 info->
cmap.green[fg_idx] >> 8);
1425 info->
cmap.blue[fg_idx] >> 8);
1436 for (i = 0; i < cursor->
image.height; i++) {
1437 int j = (cursor->
image.width + 7) >> 3;
1441 for (; j > 0; j--) {
1442 u8 data = *bitmap ^ *
mask;
1454 for (; i < 64; i++) {
1461 mask = (
u8 *)cursor->
mask;
1462 for (i = 0; i < cursor->
image.height; i++) {
1463 int j = (cursor->
image.width + 7) >> 3;
1467 for (; j > 0; j--) {
1475 for (; i < 64; i++) {
1491 static struct fb_ops pm2fb_ops = {
1493 .fb_check_var = pm2fb_check_var,
1494 .fb_set_par = pm2fb_set_par,
1495 .fb_setcolreg = pm2fb_setcolreg,
1496 .fb_blank = pm2fb_blank,
1497 .fb_pan_display = pm2fb_pan_display,
1498 .fb_fillrect = pm2fb_fillrect,
1499 .fb_copyarea = pm2fb_copyarea,
1500 .fb_imageblit = pm2fb_imageblit,
1501 .fb_sync = pm2fb_sync,
1502 .fb_cursor = pm2fb_cursor,
1535 default_par = info->
par;
1539 strcpy(pm2fb_fix.id,
"TVP4020");
1543 strcpy(pm2fb_fix.id,
"Permedia2");
1547 strcpy(pm2fb_fix.id,
"Permedia2v");
1555 #if defined(__BIG_ENDIAN)
1561 DPRINTK(
"Adjusting register base for big-endian.\n");
1563 DPRINTK(
"Register base at 0x%lx\n", pm2fb_fix.mmio_start);
1569 goto err_exit_neither;
1573 if (!default_par->
v_regs) {
1577 goto err_exit_neither;
1584 DPRINTK(
"MemControl 0x%x BootAddress 0x%x MemConfig 0x%x\n",
1597 DPRINTK(
"subsystem_vendor: %04x, "
1598 "subsystem_device: %04x\n",
1600 DPRINTK(
"We have not been initialized by VGA BIOS and "
1601 "are running on an Elsa Winner 2000 Office\n");
1602 DPRINTK(
"Initializing card timings manually...\n");
1607 DPRINTK(
"subsystem_vendor: %04x, "
1608 "subsystem_device: %04x\n",
1610 DPRINTK(
"We have not been initialized by VGA BIOS and "
1611 "are running on an 3dlabs reference board\n");
1612 DPRINTK(
"Initializing card timings manually...\n");
1620 pm2fb_fix.smem_len = 0x200000;
1623 pm2fb_fix.smem_len = 0x400000;
1626 pm2fb_fix.smem_len = 0x600000;
1629 pm2fb_fix.smem_len = 0x800000;
1657 info->
fbops = &pm2fb_ops;
1658 info->
fix = pm2fb_fix;
1667 if (!info->
pixmap.addr) {
1669 goto err_exit_pixmap;
1672 info->
pixmap.buf_align = 4;
1673 info->
pixmap.scan_align = 4;
1674 info->
pixmap.access_align = 32;
1680 info->
pixmap.scan_align = 1;
1684 mode_option =
"640x480@60";
1687 if (!err || err == 4)
1688 info->
var = pm2fb_var;
1699 info->
node, info->
fix.id, pm2fb_fix.smem_len / 1024);
1704 pci_set_drvdata(pdev, info);
1732 struct fb_info *info = pci_get_drvdata(pdev);
1741 info->
fix.smem_len);
1748 pci_set_drvdata(pdev,
NULL);
1766 .id_table = pm2fb_id_table,
1767 .probe = pm2fb_probe,
1784 if (!options || !*options)
1787 while ((this_opt =
strsep(&options,
",")) !=
NULL) {
1790 if (!
strcmp(this_opt,
"lowhsync"))
1792 else if (!
strcmp(this_opt,
"lowvsync"))
1794 else if (!
strncmp(this_opt,
"hwcursor=", 9))
1797 else if (!
strncmp(this_opt,
"nomtrr", 6))
1800 else if (!
strncmp(this_opt,
"noaccel", 7))
1803 mode_option = this_opt;
1810 static int __init pm2fb_init(
void)
1817 pm2fb_setup(option);
1820 return pci_register_driver(&pm2fb_driver);
1830 static void __exit pm2fb_exit(
void)
1842 MODULE_PARM_DESC(mode,
"Initial video mode e.g. '648x480-8@60' (deprecated)");
1844 MODULE_PARM_DESC(lowhsync,
"Force horizontal sync low regardless of mode");
1851 "(1=enable, 0=disable, default=1)");
1854 MODULE_PARM_DESC(nomtrr,
"Disable MTRR support (0 or 1=disabled) (default=0)");