25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/errno.h>
28 #include <linux/string.h>
30 #include <linux/slab.h>
34 #include <linux/pci.h>
41 #if !defined(CONFIG_PCI)
42 #error "Only generic PCI cards supported."
45 #undef PM3FB_MASTER_DEBUG
46 #ifdef PM3FB_MASTER_DEBUG
47 #define DPRINTK(a, b...) \
48 printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b)
50 #define DPRINTK(a, b...)
53 #define PM3_PIXMAP_SIZE (2048 * 4)
58 static int hwcursor = 1;
106 static inline void PM3_WRITE_REG(
struct pm3_par *par,
s32 off,
u32 v)
111 static inline void PM3_WAIT(
struct pm3_par *par,
u32 n)
117 static inline void PM3_WRITE_DAC_REG(
struct pm3_par *par,
unsigned r,
u8 v)
127 static inline void pm3fb_set_color(
struct pm3_par *par,
unsigned char regno,
128 unsigned char r,
unsigned char g,
unsigned char b)
141 static void pm3fb_clear_colormap(
struct pm3_par *par,
142 unsigned char r,
unsigned char g,
unsigned char b)
146 for (i = 0; i < 256 ; i++)
147 pm3fb_set_color(par, i, r, g, b);
152 static void pm3fb_calculate_clock(
unsigned long reqclock,
154 unsigned char *feedback,
162 for (f = 1; f < 256; f++) {
163 for (pre = 1; pre < 256; pre++) {
164 for (post = 0; post < 5; post++) {
166 currerr = (reqclock >
freq)
169 if (currerr < freqerr) {
183 return var->
red.length + var->
green.length
189 static inline int pm3fb_shift_bpp(
unsigned bpp,
int v)
199 DPRINTK(
"Unsupported depth %u\n", bpp);
210 PM3_WRITE_REG(par,
PM3Sync, 0);
220 static void pm3fb_init_engine(
struct fb_info *info)
223 const u32 width = (info->
var.xres_virtual + 7) & ~7;
295 unsigned long rm = 1 | (3 << 7);
296 switch (info->
var.bits_per_pixel) {
316 DPRINTK(1,
"Unsupported depth %d\n",
317 info->
var.bits_per_pixel);
339 info->
fix.line_length;
345 switch (info->
var.bits_per_pixel) {
348 (1 << 10) | (2 << 3));
352 (1 << 10) | (1 << 3));
356 (1 << 10) | (0 << 3));
359 DPRINTK(1,
"Unsupported depth %d\n",
360 info->current_par->depth);
367 PM3_WRITE_REG(par,
PM3dY, 1 << 16);
382 static void pm3fb_fillrect(
struct fb_info *info,
404 vxres = info->
var.xres_virtual;
405 vyres = info->
var.yres_virtual;
409 if (!modded.width || !modded.height ||
410 modded.dx >= vxres || modded.dy >= vyres)
413 if (modded.dx + modded.width > vxres)
414 modded.width = vxres - modded.dx;
415 if (modded.dy + modded.height > vyres)
416 modded.height = vyres - modded.dy;
418 if (info->
var.bits_per_pixel == 8)
420 if (info->
var.bits_per_pixel <= 16)
421 color |= color << 16;
446 static void pm3fb_copyarea(
struct fb_info *info,
452 int x_align, o_x, o_y;
463 vxres = info->
var.xres_virtual;
464 vyres = info->
var.yres_virtual;
466 if (!modded.width || !modded.height ||
467 modded.sx >= vxres || modded.sy >= vyres ||
468 modded.dx >= vxres || modded.dy >= vyres)
471 if (modded.sx + modded.width > vxres)
472 modded.width = vxres - modded.sx;
473 if (modded.dx + modded.width > vxres)
474 modded.width = vxres - modded.dx;
475 if (modded.sy + modded.height > vyres)
476 modded.height = vyres - modded.sy;
477 if (modded.dy + modded.height > vyres)
478 modded.height = vyres - modded.dy;
480 o_x = modded.sx - modded.dx;
481 o_y = modded.sy - modded.dy;
483 x_align = (modded.sx & 0x1f);
495 ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff));
497 (((modded.dy + modded.height) & 0x0fff) << 16) |
498 ((modded.dx + modded.width) & 0x0fff));
531 switch (info->
fix.visual) {
542 if (image->
depth != 1) {
547 if (info->
var.bits_per_pixel == 8) {
551 if (info->
var.bits_per_pixel <= 16) {
570 ((image->
dy & 0x0fff) << 16) | (image->
dx & 0x0fff));
572 (((image->
dy + image->
height) & 0x0fff) << 16) |
573 ((image->
dx + image->
width) & 0x0fff));
587 int width = ((image->
width + 7) >> 3)
588 + info->
pixmap.scan_align - 1;
602 PM3_WAIT(par, width + 1);
614 static const u8 cursor_bits_lookup[16] = {
615 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
616 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
628 if (cursor->
image.width > 64 ||
629 cursor->
image.height > 64 ||
630 cursor->
image.depth > 1)
648 int x = cursor->
image.dx - info->
var.xoffset;
649 int y = cursor->
image.dy - info->
var.yoffset;
659 cursor->
hot.x & 0x3f);
661 cursor->
hot.y & 0x3f);
665 u32 fg_idx = cursor->
image.fg_color;
666 u32 bg_idx = cursor->
image.bg_color;
671 cmap.
red[fg_idx] >> 8 );
673 cmap.
green[fg_idx] >> 8 );
675 cmap.
blue[fg_idx] >> 8 );
678 cmap.
red[bg_idx] >> 8 );
680 cmap.
green[bg_idx] >> 8 );
682 cmap.
blue[bg_idx] >> 8 );
691 for (i = 0; i < cursor->
image.height; i++) {
692 int j = (cursor->
image.width + 7) >> 3;
701 PM3_WRITE_DAC_REG(par, pos++,
702 cursor_bits_lookup[data >> 4] |
703 (cursor_bits_lookup[*mask >> 4] << 1));
705 PM3_WRITE_DAC_REG(par, pos++,
706 cursor_bits_lookup[data & 0xf] |
707 (cursor_bits_lookup[*mask & 0xf] << 1));
712 PM3_WRITE_DAC_REG(par, pos++, 0);
713 PM3_WRITE_DAC_REG(par, pos++, 0);
717 PM3_WRITE_DAC_REG(par, pos++, 0);
723 static void pm3fb_write_mode(
struct fb_info *info)
726 char tempsync = 0x00;
727 char tempmisc = 0x00;
728 const u32 hsstart = info->
var.right_margin;
729 const u32 hsend = hsstart + info->
var.hsync_len;
730 const u32 hbend = hsend + info->
var.left_margin;
731 const u32 xres = (info->
var.xres + 31) & ~31;
732 const u32 htotal = xres + hbend;
733 const u32 vsstart = info->
var.lower_margin;
734 const u32 vsend = vsstart + info->
var.vsync_len;
735 const u32 vbend = vsend + info->
var.upper_margin;
736 const u32 vtotal = info->
var.yres + vbend;
737 const u32 width = (info->
var.xres_virtual + 7) & ~7;
738 const unsigned bpp = info->
var.bits_per_pixel;
747 pm3fb_shift_bpp(bpp, htotal - 1));
749 pm3fb_shift_bpp(bpp, hsend));
751 pm3fb_shift_bpp(bpp, hsstart));
753 pm3fb_shift_bpp(bpp, hbend));
755 pm3fb_shift_bpp(bpp, hbend));
757 pm3fb_shift_bpp(bpp, width));
758 PM3_WRITE_REG(par,
PM3VTotal, vtotal - 1);
759 PM3_WRITE_REG(par,
PM3VsEnd, vsend - 1);
761 PM3_WRITE_REG(par,
PM3VbEnd, vbend);
804 DPRINTK(
"Unsupported depth %d\n", bpp);
824 (PM3_READ_REG(par,
PM3VClkCtl) & 0xFFFFFFFC));
836 (
void)pm3fb_calculate_clock(pixclock, &
m, &n, &
p);
838 DPRINTK(
"Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
839 pixclock, (
int)
m, (
int) n, (
int)
p);
859 DPRINTK(
"PM3RD_SyncControl: %d\n", tempsync);
863 switch (pm3fb_depth(&info->
var)) {
921 unsigned bpp = var->
red.length + var->
green.length
930 var->
green.length = 8;
931 var->
blue.length = 8;
933 var->
green.offset = 0;
934 var->
blue.offset = 0;
940 var->
blue.length = 5;
941 var->
green.length = 6;
946 var->
green.length = 8;
947 var->
blue.length = 8;
951 DPRINTK(
"depth not supported: %u\n",
958 var->
blue.offset = 0;
967 DPRINTK(
"virtual x resolution != "
968 "physical x resolution not supported\n");
973 DPRINTK(
"virtual y resolution < "
974 "physical y resolution not possible\n");
979 DPRINTK(
"xoffset not supported\n");
984 DPRINTK(
"interlace not supported\n");
991 if (var->
xres < 200 || var->
xres > 2048) {
996 if (var->
yres < 200 || var->
yres > 4095) {
1002 DPRINTK(
"no memory for screen (%ux%ux%u)\n",
1008 DPRINTK(
"pixclock too high (%ldKHz)\n",
1015 DPRINTK(
"Checking graphics mode at %dx%d depth %d\n",
1020 static int pm3fb_set_par(
struct fb_info *info)
1023 const u32 xres = (info->
var.xres + 31) & ~31;
1024 const unsigned bpp = info->
var.bits_per_pixel;
1026 par->
base = pm3fb_shift_bpp(bpp, (info->
var.yoffset * xres)
1027 + info->
var.xoffset);
1046 DPRINTK(
"PM3Video disabled\n");
1059 DPRINTK(
"Unsupported depth\n");
1065 info->
fix.line_length = ((info->
var.xres_virtual + 7) >> 3) *
bpp;
1068 pm3fb_clear_colormap(par, 0, 0, 0);
1070 pm3fb_init_engine(info);
1071 pm3fb_write_mode(info);
1075 static int pm3fb_setcolreg(
unsigned regno,
unsigned red,
unsigned green,
1086 if (info->
var.grayscale)
1087 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
1112 #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
1126 v = (red << info->
var.red.offset) |
1127 (green << info->
var.green.offset) |
1128 (blue << info->
var.blue.offset) |
1129 (transp << info->
var.transp.offset);
1131 switch (info->
var.bits_per_pixel) {
1141 pm3fb_set_color(par, regno, red, green, blue);
1150 const u32 xres = (info->
var.xres + 31) & ~31;
1152 par->
base = pm3fb_shift_bpp(info->
var.bits_per_pixel,
1160 static int pm3fb_blank(
int blank_mode,
struct fb_info *info)
1176 switch (blank_mode) {
1197 DPRINTK(
"Unsupported blanking %d\n", blank_mode);
1210 static struct fb_ops pm3fb_ops = {
1212 .fb_check_var = pm3fb_check_var,
1213 .fb_set_par = pm3fb_set_par,
1214 .fb_setcolreg = pm3fb_setcolreg,
1215 .fb_pan_display = pm3fb_pan_display,
1216 .fb_fillrect = pm3fb_fillrect,
1217 .fb_copyarea = pm3fb_copyarea,
1218 .fb_imageblit = pm3fb_imageblit,
1219 .fb_blank = pm3fb_blank,
1220 .fb_sync = pm3fb_sync,
1221 .fb_cursor = pm3fb_cursor,
1236 unsigned char __iomem *screen_mem;
1238 pm3fb_fix.smem_len = 64 * 1024
l * 1024;
1258 DPRINTK(
"PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
1266 for (i = 0; i < 32; i++) {
1268 (screen_mem + (i * 1048576)));
1270 temp1 =
fb_readl((screen_mem + (i * 1048576)));
1273 if (temp1 == (i * 0x00345678))
1279 DPRINTK(
"First detect pass already got %ld MB\n", memsize + 1);
1281 if (memsize + 1 == i) {
1282 for (i = 0; i < 32; i++) {
1284 writel(0x0000000, (screen_mem + (i * 1048576)));
1288 for (i = 32; i < 64; i++) {
1290 (screen_mem + (i * 1048576)));
1293 fb_readl((screen_mem + (i * 1048576)));
1295 fb_readl((screen_mem + ((i - 32) * 1048576)));
1297 if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
1303 DPRINTK(
"Second detect pass got %ld MB\n", memsize + 1);
1310 memsize = 1048576 * (memsize + 1);
1312 DPRINTK(
"Returning 0x%08lx bytes\n", memsize);
1346 #if defined(__BIG_ENDIAN)
1348 DPRINTK(
"Adjusting register base for big-endian.\n");
1355 goto err_exit_neither;
1363 goto err_exit_neither;
1368 pm3fb_fix.smem_len = pm3fb_size_memory(par);
1369 if (!pm3fb_fix.smem_len) {
1393 info->
fbops = &pm3fb_ops;
1397 info->
fix = pm3fb_fix;
1411 if (!info->
pixmap.addr) {
1413 goto err_exit_pixmap;
1416 info->
pixmap.buf_align = 4;
1417 info->
pixmap.scan_align = 4;
1418 info->
pixmap.access_align = 32;
1426 mode_option =
"640x480@60";
1430 if (!retval || retval == 4) {
1443 pm3fb_check_var(&info->
var, info);
1451 pci_set_drvdata(dev, info);
1474 struct fb_info *info = pci_get_drvdata(dev);
1486 info->
fix.smem_len);
1493 pci_set_drvdata(dev,
NULL);
1508 .id_table = pm3fb_id_table,
1509 .probe = pm3fb_probe,
1529 if (!options || !*options)
1532 while ((this_opt =
strsep(&options,
",")) !=
NULL) {
1535 else if (!
strncmp(this_opt,
"noaccel", 7))
1537 else if (!
strncmp(this_opt,
"hwcursor=", 9))
1540 else if (!
strncmp(this_opt,
"nomtrr", 6))
1544 mode_option = this_opt;
1550 static int __init pm3fb_init(
void)
1560 pm3fb_setup(option);
1563 return pci_register_driver(&pm3fb_driver);
1567 static void __exit pm3fb_exit(
void)
1582 "(1=enable, 0=disable, default=1)");
1585 MODULE_PARM_DESC(nomtrr,
"Disable MTRR support (0 or 1=disabled) (default=0)");