0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/fb.h>
0012 #include <linux/console.h>
0013 #include <linux/pci.h>
0014 #include <linux/pci_ids.h>
0015 #include <linux/delay.h>
0016 #include <linux/string.h>
0017
0018 #define PCI_DEVICE_ID_IBM_GXT4500P 0x21c
0019 #define PCI_DEVICE_ID_IBM_GXT6500P 0x21b
0020 #define PCI_DEVICE_ID_IBM_GXT4000P 0x16e
0021 #define PCI_DEVICE_ID_IBM_GXT6000P 0x170
0022
0023
0024
0025
0026 #define CFG_ENDIAN0 0x40
0027
0028
0029 #define STATUS 0x1000
0030 #define CTRL_REG0 0x1004
0031 #define CR0_HALT_DMA 0x4
0032 #define CR0_RASTER_RESET 0x8
0033 #define CR0_GEOM_RESET 0x10
0034 #define CR0_MEM_CTRLER_RESET 0x20
0035
0036
0037 #define FB_AB_CTRL 0x1100
0038 #define FB_CD_CTRL 0x1104
0039 #define FB_WID_CTRL 0x1108
0040 #define FB_Z_CTRL 0x110c
0041 #define FB_VGA_CTRL 0x1110
0042 #define REFRESH_AB_CTRL 0x1114
0043 #define REFRESH_CD_CTRL 0x1118
0044 #define FB_OVL_CTRL 0x111c
0045 #define FB_CTRL_TYPE 0x80000000
0046 #define FB_CTRL_WIDTH_MASK 0x007f0000
0047 #define FB_CTRL_WIDTH_SHIFT 16
0048 #define FB_CTRL_START_SEG_MASK 0x00003fff
0049
0050 #define REFRESH_START 0x1098
0051 #define REFRESH_SIZE 0x109c
0052
0053
0054 #define DFA_FB_A 0x11e0
0055 #define DFA_FB_B 0x11e4
0056 #define DFA_FB_C 0x11e8
0057 #define DFA_FB_D 0x11ec
0058 #define DFA_FB_ENABLE 0x80000000
0059 #define DFA_FB_BASE_MASK 0x03f00000
0060 #define DFA_FB_STRIDE_1k 0x00000000
0061 #define DFA_FB_STRIDE_2k 0x00000010
0062 #define DFA_FB_STRIDE_4k 0x00000020
0063 #define DFA_PIX_8BIT 0x00000000
0064 #define DFA_PIX_16BIT_565 0x00000001
0065 #define DFA_PIX_16BIT_1555 0x00000002
0066 #define DFA_PIX_24BIT 0x00000004
0067 #define DFA_PIX_32BIT 0x00000005
0068
0069
0070 static const unsigned char pixsize[] = {
0071 1, 2, 2, 2, 4, 4
0072 };
0073
0074
0075 #define DTG_CONTROL 0x1900
0076 #define DTG_CTL_SCREEN_REFRESH 2
0077 #define DTG_CTL_ENABLE 1
0078 #define DTG_HORIZ_EXTENT 0x1904
0079 #define DTG_HORIZ_DISPLAY 0x1908
0080 #define DTG_HSYNC_START 0x190c
0081 #define DTG_HSYNC_END 0x1910
0082 #define DTG_HSYNC_END_COMP 0x1914
0083 #define DTG_VERT_EXTENT 0x1918
0084 #define DTG_VERT_DISPLAY 0x191c
0085 #define DTG_VSYNC_START 0x1920
0086 #define DTG_VSYNC_END 0x1924
0087 #define DTG_VERT_SHORT 0x1928
0088
0089
0090 #define DISP_CTL 0x402c
0091 #define DISP_CTL_OFF 2
0092 #define SYNC_CTL 0x4034
0093 #define SYNC_CTL_SYNC_ON_RGB 1
0094 #define SYNC_CTL_SYNC_OFF 2
0095 #define SYNC_CTL_HSYNC_INV 8
0096 #define SYNC_CTL_VSYNC_INV 0x10
0097 #define SYNC_CTL_HSYNC_OFF 0x20
0098 #define SYNC_CTL_VSYNC_OFF 0x40
0099
0100 #define PLL_M 0x4040
0101 #define PLL_N 0x4044
0102 #define PLL_POSTDIV 0x4048
0103 #define PLL_C 0x404c
0104
0105
0106 #define CURSOR_X 0x4078
0107 #define CURSOR_Y 0x407c
0108 #define CURSOR_HOTSPOT 0x4080
0109 #define CURSOR_MODE 0x4084
0110 #define CURSOR_MODE_OFF 0
0111 #define CURSOR_MODE_4BPP 1
0112 #define CURSOR_PIXMAP 0x5000
0113 #define CURSOR_CMAP 0x7400
0114
0115
0116 #define WAT_FMT 0x4100
0117 #define WAT_FMT_24BIT 0
0118 #define WAT_FMT_16BIT_565 1
0119 #define WAT_FMT_16BIT_1555 2
0120 #define WAT_FMT_32BIT 3
0121 #define WAT_FMT_8BIT_332 9
0122 #define WAT_FMT_8BIT 0xa
0123 #define WAT_FMT_NO_CMAP 4
0124 #define WAT_CMAP_OFFSET 0x4104
0125 #define WAT_CTRL 0x4108
0126 #define WAT_CTRL_SEL_B 1
0127 #define WAT_CTRL_NO_INC 2
0128 #define WAT_GAMMA_CTRL 0x410c
0129 #define WAT_GAMMA_DISABLE 1
0130 #define WAT_OVL_CTRL 0x430c
0131
0132
0133 static const unsigned char watfmt[] = {
0134 WAT_FMT_8BIT, WAT_FMT_16BIT_565, WAT_FMT_16BIT_1555, 0,
0135 WAT_FMT_24BIT, WAT_FMT_32BIT
0136 };
0137
0138
0139 #define CMAP 0x6000
0140
0141 #define readreg(par, reg) readl((par)->regs + (reg))
0142 #define writereg(par, reg, val) writel((val), (par)->regs + (reg))
0143
0144 struct gxt4500_par {
0145 void __iomem *regs;
0146 int wc_cookie;
0147 int pixfmt;
0148
0149
0150 int refclk_ps;
0151 int pll_m;
0152 int pll_n;
0153 int pll_pd1;
0154 int pll_pd2;
0155
0156 u32 pseudo_palette[16];
0157 };
0158
0159
0160 static char *mode_option;
0161
0162
0163 static const struct fb_videomode defaultmode = {
0164 .refresh = 60,
0165 .xres = 1280,
0166 .yres = 1024,
0167 .pixclock = 9295,
0168 .left_margin = 248,
0169 .right_margin = 48,
0170 .upper_margin = 38,
0171 .lower_margin = 1,
0172 .hsync_len = 112,
0173 .vsync_len = 3,
0174 .vmode = FB_VMODE_NONINTERLACED
0175 };
0176
0177
0178 enum gxt_cards {
0179 GXT4500P,
0180 GXT6500P,
0181 GXT4000P,
0182 GXT6000P
0183 };
0184
0185
0186 static const struct cardinfo {
0187 int refclk_ps;
0188 const char *cardname;
0189 } cardinfo[] = {
0190 [GXT4500P] = { .refclk_ps = 9259, .cardname = "IBM GXT4500P" },
0191 [GXT6500P] = { .refclk_ps = 9259, .cardname = "IBM GXT6500P" },
0192 [GXT4000P] = { .refclk_ps = 40000, .cardname = "IBM GXT4000P" },
0193 [GXT6000P] = { .refclk_ps = 40000, .cardname = "IBM GXT6000P" },
0194 };
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 static const unsigned char mdivtab[] = {
0207 0x3f, 0x00, 0x20, 0x10, 0x28, 0x14, 0x2a, 0x15, 0x0a,
0208 0x25, 0x32, 0x19, 0x0c, 0x26, 0x13, 0x09, 0x04, 0x22, 0x11,
0209 0x08, 0x24, 0x12, 0x29, 0x34, 0x1a, 0x2d, 0x36, 0x1b, 0x0d,
0210 0x06, 0x23, 0x31, 0x38, 0x1c, 0x2e, 0x17, 0x0b, 0x05, 0x02,
0211 0x21, 0x30, 0x18, 0x2c, 0x16, 0x2b, 0x35, 0x3a, 0x1d, 0x0e,
0212 0x27, 0x33, 0x39, 0x3c, 0x1e, 0x2f, 0x37, 0x3b, 0x3d, 0x3e,
0213 0x1f, 0x0f, 0x07, 0x03, 0x01,
0214 };
0215
0216 static const unsigned char ndivtab[] = {
0217 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0x78, 0xbc, 0x5e,
0218 0x2f, 0x17, 0x0b, 0x85, 0xc2, 0xe1, 0x70, 0x38, 0x9c, 0x4e,
0219 0xa7, 0xd3, 0xe9, 0xf4, 0xfa, 0xfd, 0xfe, 0x7f, 0xbf, 0xdf,
0220 0xef, 0x77, 0x3b, 0x1d, 0x8e, 0xc7, 0xe3, 0x71, 0xb8, 0xdc,
0221 0x6e, 0xb7, 0x5b, 0x2d, 0x16, 0x8b, 0xc5, 0xe2, 0xf1, 0xf8,
0222 0xfc, 0x7e, 0x3f, 0x9f, 0xcf, 0x67, 0xb3, 0xd9, 0x6c, 0xb6,
0223 0xdb, 0x6d, 0x36, 0x9b, 0x4d, 0x26, 0x13, 0x89, 0xc4, 0x62,
0224 0xb1, 0xd8, 0xec, 0xf6, 0xfb, 0x7d, 0xbe, 0x5f, 0xaf, 0x57,
0225 0x2b, 0x95, 0x4a, 0x25, 0x92, 0x49, 0xa4, 0x52, 0x29, 0x94,
0226 0xca, 0x65, 0xb2, 0x59, 0x2c, 0x96, 0xcb, 0xe5, 0xf2, 0x79,
0227 0x3c, 0x1e, 0x0f, 0x07, 0x83, 0x41, 0x20, 0x90, 0x48, 0x24,
0228 0x12, 0x09, 0x84, 0x42, 0xa1, 0x50, 0x28, 0x14, 0x8a, 0x45,
0229 0xa2, 0xd1, 0xe8, 0x74, 0xba, 0xdd, 0xee, 0xf7, 0x7b, 0x3d,
0230 0x9e, 0x4f, 0x27, 0x93, 0xc9, 0xe4, 0x72, 0x39, 0x1c, 0x0e,
0231 0x87, 0xc3, 0x61, 0x30, 0x18, 0x8c, 0xc6, 0x63, 0x31, 0x98,
0232 0xcc, 0xe6, 0x73, 0xb9, 0x5c, 0x2e, 0x97, 0x4b, 0xa5, 0xd2,
0233 0x69,
0234 };
0235
0236 static int calc_pll(int period_ps, struct gxt4500_par *par)
0237 {
0238 int m, n, pdiv1, pdiv2, postdiv;
0239 int pll_period, best_error, t, intf;
0240
0241
0242 if (period_ps < 3333 || period_ps > 200000)
0243 return -1;
0244
0245 best_error = 1000000;
0246 for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) {
0247 for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) {
0248 postdiv = pdiv1 * pdiv2;
0249 pll_period = DIV_ROUND_UP(period_ps, postdiv);
0250
0251 if (pll_period < 1666 || pll_period > 2857)
0252 continue;
0253 for (m = 1; m <= 64; ++m) {
0254 intf = m * par->refclk_ps;
0255 if (intf > 500000)
0256 break;
0257 n = intf * postdiv / period_ps;
0258 if (n < 3 || n > 160)
0259 continue;
0260 t = par->refclk_ps * m * postdiv / n;
0261 t -= period_ps;
0262 if (t >= 0 && t < best_error) {
0263 par->pll_m = m;
0264 par->pll_n = n;
0265 par->pll_pd1 = pdiv1;
0266 par->pll_pd2 = pdiv2;
0267 best_error = t;
0268 }
0269 }
0270 }
0271 }
0272 if (best_error == 1000000)
0273 return -1;
0274 return 0;
0275 }
0276
0277 static int calc_pixclock(struct gxt4500_par *par)
0278 {
0279 return par->refclk_ps * par->pll_m * par->pll_pd1 * par->pll_pd2
0280 / par->pll_n;
0281 }
0282
0283 static int gxt4500_var_to_par(struct fb_var_screeninfo *var,
0284 struct gxt4500_par *par)
0285 {
0286 if (var->xres + var->xoffset > var->xres_virtual ||
0287 var->yres + var->yoffset > var->yres_virtual ||
0288 var->xres_virtual > 4096)
0289 return -EINVAL;
0290 if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
0291 return -EINVAL;
0292
0293 if (calc_pll(var->pixclock, par) < 0)
0294 return -EINVAL;
0295
0296 switch (var->bits_per_pixel) {
0297 case 32:
0298 if (var->transp.length)
0299 par->pixfmt = DFA_PIX_32BIT;
0300 else
0301 par->pixfmt = DFA_PIX_24BIT;
0302 break;
0303 case 24:
0304 par->pixfmt = DFA_PIX_24BIT;
0305 break;
0306 case 16:
0307 if (var->green.length == 5)
0308 par->pixfmt = DFA_PIX_16BIT_1555;
0309 else
0310 par->pixfmt = DFA_PIX_16BIT_565;
0311 break;
0312 case 8:
0313 par->pixfmt = DFA_PIX_8BIT;
0314 break;
0315 default:
0316 return -EINVAL;
0317 }
0318
0319 return 0;
0320 }
0321
0322 static const struct fb_bitfield eightbits = {0, 8};
0323 static const struct fb_bitfield nobits = {0, 0};
0324
0325 static void gxt4500_unpack_pixfmt(struct fb_var_screeninfo *var,
0326 int pixfmt)
0327 {
0328 var->bits_per_pixel = pixsize[pixfmt] * 8;
0329 var->red = eightbits;
0330 var->green = eightbits;
0331 var->blue = eightbits;
0332 var->transp = nobits;
0333
0334 switch (pixfmt) {
0335 case DFA_PIX_16BIT_565:
0336 var->red.length = 5;
0337 var->green.length = 6;
0338 var->blue.length = 5;
0339 break;
0340 case DFA_PIX_16BIT_1555:
0341 var->red.length = 5;
0342 var->green.length = 5;
0343 var->blue.length = 5;
0344 var->transp.length = 1;
0345 break;
0346 case DFA_PIX_32BIT:
0347 var->transp.length = 8;
0348 break;
0349 }
0350 if (pixfmt != DFA_PIX_8BIT) {
0351 var->blue.offset = 0;
0352 var->green.offset = var->blue.length;
0353 var->red.offset = var->green.offset + var->green.length;
0354 if (var->transp.length)
0355 var->transp.offset =
0356 var->red.offset + var->red.length;
0357 }
0358 }
0359
0360 static int gxt4500_check_var(struct fb_var_screeninfo *var,
0361 struct fb_info *info)
0362 {
0363 struct gxt4500_par par;
0364 int err;
0365
0366 par = *(struct gxt4500_par *)info->par;
0367 err = gxt4500_var_to_par(var, &par);
0368 if (!err) {
0369 var->pixclock = calc_pixclock(&par);
0370 gxt4500_unpack_pixfmt(var, par.pixfmt);
0371 }
0372 return err;
0373 }
0374
0375 static int gxt4500_set_par(struct fb_info *info)
0376 {
0377 struct gxt4500_par *par = info->par;
0378 struct fb_var_screeninfo *var = &info->var;
0379 int err;
0380 u32 ctrlreg, tmp;
0381 unsigned int dfa_ctl, pixfmt, stride;
0382 unsigned int wid_tiles, i;
0383 unsigned int prefetch_pix, htot;
0384 struct gxt4500_par save_par;
0385
0386 save_par = *par;
0387 err = gxt4500_var_to_par(var, par);
0388 if (err) {
0389 *par = save_par;
0390 return err;
0391 }
0392
0393
0394 ctrlreg = readreg(par, DTG_CONTROL);
0395 ctrlreg &= ~(DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH);
0396 writereg(par, DTG_CONTROL, ctrlreg);
0397
0398
0399 tmp = readreg(par, PLL_C) & ~0x7f;
0400 if (par->pll_n < 38)
0401 tmp |= 0x29;
0402 if (par->pll_n < 69)
0403 tmp |= 0x35;
0404 else if (par->pll_n < 100)
0405 tmp |= 0x76;
0406 else
0407 tmp |= 0x7e;
0408 writereg(par, PLL_C, tmp);
0409 writereg(par, PLL_M, mdivtab[par->pll_m - 1]);
0410 writereg(par, PLL_N, ndivtab[par->pll_n - 2]);
0411 tmp = ((8 - par->pll_pd2) << 3) | (8 - par->pll_pd1);
0412 if (par->pll_pd1 == 8 || par->pll_pd2 == 8) {
0413
0414 writereg(par, PLL_POSTDIV, tmp | 0x9);
0415 udelay(1);
0416 }
0417 writereg(par, PLL_POSTDIV, tmp);
0418 msleep(20);
0419
0420
0421 writereg(par, CURSOR_MODE, CURSOR_MODE_OFF);
0422
0423
0424 writereg(par, CTRL_REG0, CR0_RASTER_RESET | (CR0_RASTER_RESET << 16));
0425 udelay(10);
0426 writereg(par, CTRL_REG0, CR0_RASTER_RESET << 16);
0427
0428
0429 htot = var->xres + var->left_margin + var->right_margin +
0430 var->hsync_len;
0431 writereg(par, DTG_HORIZ_EXTENT, htot - 1);
0432 writereg(par, DTG_HORIZ_DISPLAY, var->xres - 1);
0433 writereg(par, DTG_HSYNC_START, var->xres + var->right_margin - 1);
0434 writereg(par, DTG_HSYNC_END,
0435 var->xres + var->right_margin + var->hsync_len - 1);
0436 writereg(par, DTG_HSYNC_END_COMP,
0437 var->xres + var->right_margin + var->hsync_len - 1);
0438 writereg(par, DTG_VERT_EXTENT,
0439 var->yres + var->upper_margin + var->lower_margin +
0440 var->vsync_len - 1);
0441 writereg(par, DTG_VERT_DISPLAY, var->yres - 1);
0442 writereg(par, DTG_VSYNC_START, var->yres + var->lower_margin - 1);
0443 writereg(par, DTG_VSYNC_END,
0444 var->yres + var->lower_margin + var->vsync_len - 1);
0445 prefetch_pix = 3300000 / var->pixclock;
0446 if (prefetch_pix >= htot)
0447 prefetch_pix = htot - 1;
0448 writereg(par, DTG_VERT_SHORT, htot - prefetch_pix - 1);
0449 ctrlreg |= DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH;
0450 writereg(par, DTG_CONTROL, ctrlreg);
0451
0452
0453 if (var->xres_virtual > 2048) {
0454 stride = 4096;
0455 dfa_ctl = DFA_FB_STRIDE_4k;
0456 } else if (var->xres_virtual > 1024) {
0457 stride = 2048;
0458 dfa_ctl = DFA_FB_STRIDE_2k;
0459 } else {
0460 stride = 1024;
0461 dfa_ctl = DFA_FB_STRIDE_1k;
0462 }
0463
0464
0465 wid_tiles = (var->xres_virtual + 63) >> 6;
0466
0467
0468 writereg(par, FB_AB_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
0469 writereg(par, REFRESH_AB_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
0470 writereg(par, FB_CD_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
0471 writereg(par, REFRESH_CD_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
0472 writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
0473 writereg(par, REFRESH_SIZE, (var->xres << 16) | var->yres);
0474
0475
0476
0477 pixfmt = par->pixfmt;
0478 dfa_ctl |= DFA_FB_ENABLE | pixfmt;
0479 writereg(par, DFA_FB_A, dfa_ctl);
0480
0481
0482
0483
0484
0485
0486 for (i = 0; i < 32; ++i) {
0487 writereg(par, WAT_FMT + (i << 4), watfmt[pixfmt]);
0488 writereg(par, WAT_CMAP_OFFSET + (i << 4), 0);
0489 writereg(par, WAT_CTRL + (i << 4), 0);
0490 writereg(par, WAT_GAMMA_CTRL + (i << 4), WAT_GAMMA_DISABLE);
0491 }
0492
0493
0494 ctrlreg = readreg(par, SYNC_CTL) &
0495 ~(SYNC_CTL_SYNC_ON_RGB | SYNC_CTL_HSYNC_INV |
0496 SYNC_CTL_VSYNC_INV);
0497 if (var->sync & FB_SYNC_ON_GREEN)
0498 ctrlreg |= SYNC_CTL_SYNC_ON_RGB;
0499 if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
0500 ctrlreg |= SYNC_CTL_HSYNC_INV;
0501 if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
0502 ctrlreg |= SYNC_CTL_VSYNC_INV;
0503 writereg(par, SYNC_CTL, ctrlreg);
0504
0505 info->fix.line_length = stride * pixsize[pixfmt];
0506 info->fix.visual = (pixfmt == DFA_PIX_8BIT)? FB_VISUAL_PSEUDOCOLOR:
0507 FB_VISUAL_DIRECTCOLOR;
0508
0509 return 0;
0510 }
0511
0512 static int gxt4500_setcolreg(unsigned int reg, unsigned int red,
0513 unsigned int green, unsigned int blue,
0514 unsigned int transp, struct fb_info *info)
0515 {
0516 u32 cmap_entry;
0517 struct gxt4500_par *par = info->par;
0518
0519 if (reg > 1023)
0520 return 1;
0521 cmap_entry = ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) |
0522 (green & 0xff00) | (blue >> 8);
0523 writereg(par, CMAP + reg * 4, cmap_entry);
0524
0525 if (reg < 16 && par->pixfmt != DFA_PIX_8BIT) {
0526 u32 *pal = info->pseudo_palette;
0527 u32 val = reg;
0528 switch (par->pixfmt) {
0529 case DFA_PIX_16BIT_565:
0530 val |= (reg << 11) | (reg << 5);
0531 break;
0532 case DFA_PIX_16BIT_1555:
0533 val |= (reg << 10) | (reg << 5);
0534 break;
0535 case DFA_PIX_32BIT:
0536 val |= (reg << 24);
0537 fallthrough;
0538 case DFA_PIX_24BIT:
0539 val |= (reg << 16) | (reg << 8);
0540 break;
0541 }
0542 pal[reg] = val;
0543 }
0544
0545 return 0;
0546 }
0547
0548 static int gxt4500_pan_display(struct fb_var_screeninfo *var,
0549 struct fb_info *info)
0550 {
0551 struct gxt4500_par *par = info->par;
0552
0553 if (var->xoffset & 7)
0554 return -EINVAL;
0555 if (var->xoffset + info->var.xres > info->var.xres_virtual ||
0556 var->yoffset + info->var.yres > info->var.yres_virtual)
0557 return -EINVAL;
0558
0559 writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
0560 return 0;
0561 }
0562
0563 static int gxt4500_blank(int blank, struct fb_info *info)
0564 {
0565 struct gxt4500_par *par = info->par;
0566 int ctrl, dctl;
0567
0568 ctrl = readreg(par, SYNC_CTL);
0569 ctrl &= ~(SYNC_CTL_SYNC_OFF | SYNC_CTL_HSYNC_OFF | SYNC_CTL_VSYNC_OFF);
0570 dctl = readreg(par, DISP_CTL);
0571 dctl |= DISP_CTL_OFF;
0572 switch (blank) {
0573 case FB_BLANK_UNBLANK:
0574 dctl &= ~DISP_CTL_OFF;
0575 break;
0576 case FB_BLANK_POWERDOWN:
0577 ctrl |= SYNC_CTL_SYNC_OFF;
0578 break;
0579 case FB_BLANK_HSYNC_SUSPEND:
0580 ctrl |= SYNC_CTL_HSYNC_OFF;
0581 break;
0582 case FB_BLANK_VSYNC_SUSPEND:
0583 ctrl |= SYNC_CTL_VSYNC_OFF;
0584 break;
0585 default: ;
0586 }
0587 writereg(par, SYNC_CTL, ctrl);
0588 writereg(par, DISP_CTL, dctl);
0589
0590 return 0;
0591 }
0592
0593 static const struct fb_fix_screeninfo gxt4500_fix = {
0594 .id = "IBM GXT4500P",
0595 .type = FB_TYPE_PACKED_PIXELS,
0596 .visual = FB_VISUAL_PSEUDOCOLOR,
0597 .xpanstep = 8,
0598 .ypanstep = 1,
0599 .mmio_len = 0x20000,
0600 };
0601
0602 static const struct fb_ops gxt4500_ops = {
0603 .owner = THIS_MODULE,
0604 .fb_check_var = gxt4500_check_var,
0605 .fb_set_par = gxt4500_set_par,
0606 .fb_setcolreg = gxt4500_setcolreg,
0607 .fb_pan_display = gxt4500_pan_display,
0608 .fb_blank = gxt4500_blank,
0609 .fb_fillrect = cfb_fillrect,
0610 .fb_copyarea = cfb_copyarea,
0611 .fb_imageblit = cfb_imageblit,
0612 };
0613
0614
0615 static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
0616 {
0617 int err;
0618 unsigned long reg_phys, fb_phys;
0619 struct gxt4500_par *par;
0620 struct fb_info *info;
0621 struct fb_var_screeninfo var;
0622 enum gxt_cards cardtype;
0623
0624 err = pci_enable_device(pdev);
0625 if (err) {
0626 dev_err(&pdev->dev, "gxt4500: cannot enable PCI device: %d\n",
0627 err);
0628 return err;
0629 }
0630
0631 reg_phys = pci_resource_start(pdev, 0);
0632 if (!request_mem_region(reg_phys, pci_resource_len(pdev, 0),
0633 "gxt4500 regs")) {
0634 dev_err(&pdev->dev, "gxt4500: cannot get registers\n");
0635 goto err_nodev;
0636 }
0637
0638 fb_phys = pci_resource_start(pdev, 1);
0639 if (!request_mem_region(fb_phys, pci_resource_len(pdev, 1),
0640 "gxt4500 FB")) {
0641 dev_err(&pdev->dev, "gxt4500: cannot get framebuffer\n");
0642 goto err_free_regs;
0643 }
0644
0645 info = framebuffer_alloc(sizeof(struct gxt4500_par), &pdev->dev);
0646 if (!info)
0647 goto err_free_fb;
0648
0649 par = info->par;
0650 cardtype = ent->driver_data;
0651 par->refclk_ps = cardinfo[cardtype].refclk_ps;
0652 info->fix = gxt4500_fix;
0653 strscpy(info->fix.id, cardinfo[cardtype].cardname,
0654 sizeof(info->fix.id));
0655 info->pseudo_palette = par->pseudo_palette;
0656
0657 info->fix.mmio_start = reg_phys;
0658 par->regs = pci_ioremap_bar(pdev, 0);
0659 if (!par->regs) {
0660 dev_err(&pdev->dev, "gxt4500: cannot map registers\n");
0661 goto err_free_all;
0662 }
0663
0664 info->fix.smem_start = fb_phys;
0665 info->fix.smem_len = pci_resource_len(pdev, 1);
0666 info->screen_base = pci_ioremap_wc_bar(pdev, 1);
0667 if (!info->screen_base) {
0668 dev_err(&pdev->dev, "gxt4500: cannot map framebuffer\n");
0669 goto err_unmap_regs;
0670 }
0671
0672 pci_set_drvdata(pdev, info);
0673
0674 par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,
0675 info->fix.smem_len);
0676
0677 #ifdef __BIG_ENDIAN
0678
0679 pci_write_config_dword(pdev, CFG_ENDIAN0, 0x333300);
0680 #else
0681
0682 pci_write_config_dword(pdev, CFG_ENDIAN0, 0x2300);
0683
0684 pci_write_config_dword(pdev, CFG_ENDIAN0 + 8, 0x98530000);
0685 #endif
0686
0687 info->fbops = &gxt4500_ops;
0688 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_XPAN |
0689 FBINFO_HWACCEL_YPAN;
0690
0691 err = fb_alloc_cmap(&info->cmap, 256, 0);
0692 if (err) {
0693 dev_err(&pdev->dev, "gxt4500: cannot allocate cmap\n");
0694 goto err_unmap_all;
0695 }
0696
0697 gxt4500_blank(FB_BLANK_UNBLANK, info);
0698
0699 if (!fb_find_mode(&var, info, mode_option, NULL, 0, &defaultmode, 8)) {
0700 dev_err(&pdev->dev, "gxt4500: cannot find valid video mode\n");
0701 goto err_free_cmap;
0702 }
0703 info->var = var;
0704 if (gxt4500_set_par(info)) {
0705 printk(KERN_ERR "gxt4500: cannot set video mode\n");
0706 goto err_free_cmap;
0707 }
0708
0709 if (register_framebuffer(info) < 0) {
0710 dev_err(&pdev->dev, "gxt4500: cannot register framebuffer\n");
0711 goto err_free_cmap;
0712 }
0713 fb_info(info, "%s frame buffer device\n", info->fix.id);
0714
0715 return 0;
0716
0717 err_free_cmap:
0718 fb_dealloc_cmap(&info->cmap);
0719 err_unmap_all:
0720 iounmap(info->screen_base);
0721 err_unmap_regs:
0722 iounmap(par->regs);
0723 err_free_all:
0724 framebuffer_release(info);
0725 err_free_fb:
0726 release_mem_region(fb_phys, pci_resource_len(pdev, 1));
0727 err_free_regs:
0728 release_mem_region(reg_phys, pci_resource_len(pdev, 0));
0729 err_nodev:
0730 return -ENODEV;
0731 }
0732
0733 static void gxt4500_remove(struct pci_dev *pdev)
0734 {
0735 struct fb_info *info = pci_get_drvdata(pdev);
0736 struct gxt4500_par *par;
0737
0738 if (!info)
0739 return;
0740 par = info->par;
0741 unregister_framebuffer(info);
0742 arch_phys_wc_del(par->wc_cookie);
0743 fb_dealloc_cmap(&info->cmap);
0744 iounmap(par->regs);
0745 iounmap(info->screen_base);
0746 release_mem_region(pci_resource_start(pdev, 0),
0747 pci_resource_len(pdev, 0));
0748 release_mem_region(pci_resource_start(pdev, 1),
0749 pci_resource_len(pdev, 1));
0750 framebuffer_release(info);
0751 }
0752
0753
0754 static const struct pci_device_id gxt4500_pci_tbl[] = {
0755 { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P),
0756 .driver_data = GXT4500P },
0757 { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6500P),
0758 .driver_data = GXT6500P },
0759 { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4000P),
0760 .driver_data = GXT4000P },
0761 { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6000P),
0762 .driver_data = GXT6000P },
0763 { 0 }
0764 };
0765
0766 MODULE_DEVICE_TABLE(pci, gxt4500_pci_tbl);
0767
0768 static struct pci_driver gxt4500_driver = {
0769 .name = "gxt4500",
0770 .id_table = gxt4500_pci_tbl,
0771 .probe = gxt4500_probe,
0772 .remove = gxt4500_remove,
0773 };
0774
0775 static int gxt4500_init(void)
0776 {
0777 #ifndef MODULE
0778 if (fb_get_options("gxt4500", &mode_option))
0779 return -ENODEV;
0780 #endif
0781
0782 return pci_register_driver(&gxt4500_driver);
0783 }
0784 module_init(gxt4500_init);
0785
0786 static void __exit gxt4500_exit(void)
0787 {
0788 pci_unregister_driver(&gxt4500_driver);
0789 }
0790 module_exit(gxt4500_exit);
0791
0792 MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
0793 MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6500P and GXT4000P/6000P");
0794 MODULE_LICENSE("GPL");
0795 module_param(mode_option, charp, 0);
0796 MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");