19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/string.h>
29 #include <linux/pci.h>
33 #if defined(CONFIG_PPC)
34 #include <linux/nvram.h>
36 #include <asm/pci-bridge.h>
275 static struct initvalues tvp_initregs[] __devinitdata = {
331 #define USE_NV_MODES 1
333 #define INIT_XRES 640
334 #define INIT_YRES 480
336 static int inverse = 0;
338 #if defined(CONFIG_PPC)
339 static signed char init_vmode __devinitdata = -1, init_cmode __devinitdata = -1;
344 0x0002, 0x0006, 0x0026, 0x0028, 0x0003, 0x0016, 0x0196, 0x0197, 0x0196,
346 { 0x3c, 0x3b, 0x39 }, { 0xf3, 0xf3, 0xf3 }
351 0x0004, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d, 0x020a,
353 { 0x39, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
358 0x0005, 0x000e, 0x0040, 0x0042, 0x0003, 0x018, 0x270, 0x271, 0x270,
360 { 0x3a, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
365 0x0004, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b, 0x0000,
367 { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
372 0x0006, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324, 0x0000,
374 { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
379 0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000,
381 { 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
386 0x0009, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8, 0x03e7,
388 { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
393 0x0009, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a, 0x0000,
395 { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
402 static void imsttfb_remove(
struct pci_dev *pdev);
407 static inline u32 read_reg_le32(
volatile u32 __iomem *base,
int regindex)
410 return in_le32(base + regindex);
412 return readl(base + regindex);
416 static inline void write_reg_le32(
volatile u32 __iomem *base,
int regindex,
u32 val)
421 writel(val, base + regindex);
430 clk_m = par->
init.pclk_m;
431 clk_n = par->
init.pclk_n;
432 clk_p = par->
init.pclk_p;
434 return 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
440 __u32 clk_m, clk_n,
x, stage, spilled;
453 x = 20 * (clk_m + 1) / (clk_n + 1);
459 }
else if (spilled && x < MHz) {
464 par->
init.pclk_m = clk_m;
465 par->
init.pclk_n = clk_n;
466 par->
init.pclk_p = 0;
470 compute_imstt_regvals_ibm(
struct imstt_par *par,
int xres,
int yres)
477 hes = 0x0008; heb = 0x0012; veb = 0x002a; htp = 10; vtp = 2;
481 hes = 0x0005; heb = 0x0020; veb = 0x0028; htp = 8; vtp = 3;
485 hes = 0x000a; heb = 0x001c; veb = 0x0020; htp = 8; vtp = 3;
489 hes = 0x0012; heb = 0x0022; veb = 0x0031; htp = 4; vtp = 3;
493 hes = 0x0012; heb = 0x002f; veb = 0x0029; htp = 4; vtp = 1;
494 MHz = yres == 960 ? 126 : 135;
497 hes = 0x0018; heb = 0x0040; veb = 0x002a; htp = 4; vtp = 3;
508 init->
hsb = init->
heb + (xres >> 3);
509 init->
ht = init->
hsb + htp;
512 init->
vsb = init->
veb + yres;
513 init->
vt = init->
vsb + vtp;
521 compute_imstt_regvals_tvp(
struct imstt_par *par,
int xres,
int yres)
527 init = &tvp_reg_init_2;
530 init = &tvp_reg_init_6;
533 init = &tvp_reg_init_12;
536 init = &tvp_reg_init_13;
539 init = &tvp_reg_init_17;
542 init = &tvp_reg_init_18;
545 init = yres == 960 ? &tvp_reg_init_19 : &tvp_reg_init_20;
558 return compute_imstt_regvals_ibm(par, xres, yres);
560 return compute_imstt_regvals_tvp(par, xres, yres);
567 __u8 pformat = (bpp >> 3) + 2;
663 set_imstt_regvals_ibm(par, bpp);
665 set_imstt_regvals_tvp(par, bpp);
682 pitch = init->
pitch >> 2;
687 pitch = init->
pitch >> 1;
730 switch (info->
fix.smem_len) {
732 scr = 0x059d | byteswap;
738 scr = 0x150dd | byteswap;
743 write_reg_le32(par->
dc_regs, SPR, pitch);
752 + ((var->
xoffset * (info->
var.bits_per_pixel >> 3)) >> 3);
800 var->
green.offset = 0;
801 var->
green.length = 8;
802 var->
blue.offset = 0;
803 var->
blue.length = 8;
808 if (var->
green.length != 6)
809 var->
red.offset = 10;
811 var->
green.offset = 5;
812 if (var->
green.length != 6)
813 var->
green.length = 5;
814 var->
blue.offset = 0;
815 var->
blue.length = 5;
820 var->
red.offset = 16;
822 var->
green.offset = 8;
823 var->
green.length = 8;
824 var->
blue.offset = 0;
825 var->
blue.length = 8;
830 var->
red.offset = 16;
832 var->
green.offset = 8;
833 var->
green.length = 8;
834 var->
blue.offset = 0;
835 var->
blue.length = 8;
848 var->
red.msb_right = 0;
849 var->
green.msb_right = 0;
850 var->
blue.msb_right = 0;
851 var->
transp.msb_right = 0;
862 imsttfb_set_par(
struct fb_info *info)
866 if (!compute_imstt_regvals(par, info->
var.xres, info->
var.yres))
869 if (info->
var.green.length == 6)
873 set_imstt_regvals(info, info->
var.bits_per_pixel);
874 info->
var.pixclock = 1000000 / getclkMHz(par);
883 u_int bpp = info->
var.bits_per_pixel;
907 (regno << (info->
var.green.length ==
908 5 ? 10 : 11)) | (regno << 5) | regno;
912 (regno << 16) | (regno << 8) | regno;
915 int i = (regno << 8) | regno;
916 par->
palette[regno] = (i << 16) |i;
932 set_offset(var, info);
937 imsttfb_blank(
int blank,
struct fb_info *info)
1000 Bpp = info->
var.bits_per_pixel >> 3,
1001 line_pitch = info->
fix.line_length;
1003 dy = rect->
dy * line_pitch;
1004 dx = rect->
dx * Bpp;
1007 width = rect->
width * Bpp;
1013 write_reg_le32(par->
dc_regs,
CNT, (height << 16) | width);
1015 write_reg_le32(par->
dc_regs,
BI, 0xffffffff);
1016 write_reg_le32(par->
dc_regs,
MBC, 0xffffffff);
1025 write_reg_le32(par->
dc_regs,
CNT, (height << 16) | width);
1027 write_reg_le32(par->
dc_regs,
SP, line_pitch);
1038 __u32 Bpp, line_pitch, fb_offset_old, fb_offset_new,
sp, dp_octl;
1041 Bpp = info->
var.bits_per_pixel >> 3,
1043 sx = area->
sx * Bpp;
1045 dx = area->
dx * Bpp;
1049 width = area->
width * Bpp;
1052 line_pitch = info->
fix.line_length;
1054 sp = line_pitch << 16;
1060 sp |= -(line_pitch) & 0xffff;
1061 dp_octl = -(line_pitch) & 0xffff;
1064 dp_octl = line_pitch;
1070 cnt |= -(
width) & 0xffff;
1074 fb_offset_old = sy * line_pitch +
sx;
1075 fb_offset_new = dy * line_pitch + dx;
1078 write_reg_le32(par->
dc_regs,
S1SA, fb_offset_old);
1080 write_reg_le32(par->
dc_regs,
DSA, fb_offset_new);
1090 imsttfb_load_cursor_image(
struct imstt_par *par,
int width,
int height,
__u8 fgc)
1094 if (width > 32 || height > 32)
1099 for (x = 0; x < 0x100; x++) {
1104 for (y = 0; y <
height; y++)
1105 for (x = 0; x < width >> 2; x++) {
1132 for (x = 0; x < 0x200; x++) {
1135 for (x = 0; x < 0x200; x++) {
1140 for (y = 0; y <
height; y++)
1141 for (x = 0; x < width >> 3; x++) {
1147 for (y = 0; y <
height; y++)
1148 for (x = 0; x < width >> 3; x++) {
1153 for (x = 0; x < 12; x++) {
1186 __u16 x = d->
dx + 0x40, y = d->
dy + 0x40;
1207 imstt_set_cursor(info, cursor, 0);
1210 xx = cursor->
image.dx - info->
var.xoffset;
1211 yy = cursor->
image.dy - info->
var.yoffset;
1218 int fg_idx = cursor->
image.fg_color;
1219 int width = (cursor->
image.width+7)/8;
1221 u8 *
dst = (
u8 *) cursor->dest;
1224 switch (cursor->
rop) {
1226 for (
i = 0;
i < cursor->
image.height;
i++) {
1229 data[d_idx] = byte_rev[dat[s_idx] ^
1231 mask[d_idx] = byte_rev[msk[s_idx]];
1238 for (
i = 0;
i < cursor->
image.height;
i++) {
1241 data[d_idx] = byte_rev[dat[s_idx]];
1242 mask[d_idx] = byte_rev[msk[s_idx]];
1249 fg = ((info->
cmap.red[fg_idx] & 0xf8) << 7) |
1250 ((info->
cmap.green[fg_idx] & 0xf8) << 2) |
1251 ((info->
cmap.blue[fg_idx] & 0xf8) >> 3) | 1 << 15;
1253 imsttfb_load_cursor_image(par, xx, yy, fgc);
1256 imstt_set_cursor(info, cursor, 1);
1261 #define FBIMSTT_SETREG 0x545401
1262 #define FBIMSTT_GETREG 0x545402
1263 #define FBIMSTT_SETCMAPREG 0x545403
1264 #define FBIMSTT_GETCMAPREG 0x545404
1265 #define FBIMSTT_SETIDXREG 0x545405
1266 #define FBIMSTT_GETIDXREG 0x545406
1278 if (
copy_from_user(reg, argp, 8) || reg[0] > (0x1000 -
sizeof(reg[0])) /
sizeof(reg[0]))
1280 write_reg_le32(par->
dc_regs, reg[0], reg[1]);
1283 if (
copy_from_user(reg, argp, 4) || reg[0] > (0x1000 -
sizeof(reg[0])) /
sizeof(reg[0]))
1285 reg[1] = read_reg_le32(par->
dc_regs, reg[0]);
1290 if (
copy_from_user(reg, argp, 8) || reg[0] > (0x1000 -
sizeof(reg[0])) /
sizeof(reg[0]))
1295 if (
copy_from_user(reg, argp, 4) || reg[0] > (0x1000 -
sizeof(reg[0])) /
sizeof(reg[0]))
1332 static struct pci_driver imsttfb_pci_driver = {
1334 .id_table = imsttfb_pci_tbl,
1335 .probe = imsttfb_probe,
1339 static struct fb_ops imsttfb_ops = {
1341 .fb_check_var = imsttfb_check_var,
1342 .fb_set_par = imsttfb_set_par,
1343 .fb_setcolreg = imsttfb_setcolreg,
1344 .fb_pan_display = imsttfb_pan_display,
1345 .fb_blank = imsttfb_blank,
1346 .fb_fillrect = imsttfb_fillrect,
1347 .fb_copyarea = imsttfb_copyarea,
1349 .fb_ioctl = imsttfb_ioctl,
1353 init_imstt(
struct fb_info *info)
1360 info->
fix.smem_len = (tmp & 0x0004) ? 0x400000 : 0x200000;
1362 info->
fix.smem_len = 0x800000;
1380 for (i = 0; i <
ARRAY_SIZE(ibm_initregs); i++) {
1387 for (i = 0; i <
ARRAY_SIZE(tvp_initregs); i++) {
1395 #if USE_NV_MODES && defined(CONFIG_PPC32)
1397 int vmode = init_vmode, cmode = init_cmode;
1406 if (cmode < CMODE_8 || cmode >
CMODE_32)
1421 if ((info->
var.xres * info->
var.yres) * (info->
var.bits_per_pixel >> 3) > info->
fix.smem_len
1422 || !(compute_imstt_regvals(par, info->
var.xres, info->
var.yres))) {
1423 printk(
"imsttfb: %ux%ux%u not supported\n", info->
var.xres, info->
var.yres, info->
var.bits_per_pixel);
1429 info->
fix.mmio_len = 0x1000;
1434 info->
fix.line_length = info->
var.xres * (info->
var.bits_per_pixel >> 3);
1435 info->
fix.xpanstep = 8;
1436 info->
fix.ypanstep = 1;
1437 info->
fix.ywrapstep = 0;
1443 if (info->
var.green.length == 6)
1447 set_imstt_regvals(info, info->
var.bits_per_pixel);
1449 info->
var.pixclock = 1000000 / getclkMHz(par);
1451 info->
fbops = &imsttfb_ops;
1465 printk(
"fb%u: %s frame buffer; %uMB vram; chip version %u\n",
1466 info->
node, info->
fix.id, info->
fix.smem_len >> 20, tmp);
1475 #ifdef CONFIG_PPC_OF
1478 dp = pci_device_to_OF_node(pdev);
1506 #ifdef CONFIG_PPC_OF
1507 if (dp && ((
strcmp(dp->
name,
"IMS,tt128mb8") == 0) ||
1517 "contact maintainer.\n", pdev->
device);
1525 0x400000 : 0x800000);
1526 info->
fix.mmio_start = addr + 0x800000;
1533 pci_set_drvdata(pdev, info);
1538 imsttfb_remove(
struct pci_dev *pdev)
1540 struct fb_info *info = pci_get_drvdata(pdev);
1558 if (!options || !*options)
1561 while ((this_opt =
strsep(&options,
",")) !=
NULL) {
1562 if (!
strncmp(this_opt,
"font:", 5)) {
1567 for (i = 0; i <
sizeof(fontname) - 1; i++)
1568 if (!*p || *p ==
' ' || *p ==
',')
1570 memcpy(fontname, this_opt + 5, i);
1572 }
else if (!
strncmp(this_opt,
"inverse", 7)) {
1576 #if defined(CONFIG_PPC)
1577 else if (!
strncmp(this_opt,
"vmode:", 6)) {
1581 }
else if (!
strncmp(this_opt,
"cmode:", 6)) {
1607 static int __init imsttfb_init(
void)
1615 imsttfb_setup(option);
1617 return pci_register_driver(&imsttfb_pci_driver);
1620 static void __exit imsttfb_exit(
void)