1
2
3
4
5
6
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/fb.h>
11#include <linux/console.h>
12#include <linux/pci.h>
13#include <linux/pci_ids.h>
14#include <linux/delay.h>
15#include <linux/string.h>
16
17#define PCI_DEVICE_ID_IBM_GXT4500P 0x21c
18#define PCI_DEVICE_ID_IBM_GXT6500P 0x21b
19#define PCI_DEVICE_ID_IBM_GXT4000P 0x16e
20#define PCI_DEVICE_ID_IBM_GXT6000P 0x170
21
22
23
24
25#define CFG_ENDIAN0 0x40
26
27
28#define STATUS 0x1000
29#define CTRL_REG0 0x1004
30#define CR0_HALT_DMA 0x4
31#define CR0_RASTER_RESET 0x8
32#define CR0_GEOM_RESET 0x10
33#define CR0_MEM_CTRLER_RESET 0x20
34
35
36#define FB_AB_CTRL 0x1100
37#define FB_CD_CTRL 0x1104
38#define FB_WID_CTRL 0x1108
39#define FB_Z_CTRL 0x110c
40#define FB_VGA_CTRL 0x1110
41#define REFRESH_AB_CTRL 0x1114
42#define REFRESH_CD_CTRL 0x1118
43#define FB_OVL_CTRL 0x111c
44#define FB_CTRL_TYPE 0x80000000
45#define FB_CTRL_WIDTH_MASK 0x007f0000
46#define FB_CTRL_WIDTH_SHIFT 16
47#define FB_CTRL_START_SEG_MASK 0x00003fff
48
49#define REFRESH_START 0x1098
50#define REFRESH_SIZE 0x109c
51
52
53#define DFA_FB_A 0x11e0
54#define DFA_FB_B 0x11e4
55#define DFA_FB_C 0x11e8
56#define DFA_FB_D 0x11ec
57#define DFA_FB_ENABLE 0x80000000
58#define DFA_FB_BASE_MASK 0x03f00000
59#define DFA_FB_STRIDE_1k 0x00000000
60#define DFA_FB_STRIDE_2k 0x00000010
61#define DFA_FB_STRIDE_4k 0x00000020
62#define DFA_PIX_8BIT 0x00000000
63#define DFA_PIX_16BIT_565 0x00000001
64#define DFA_PIX_16BIT_1555 0x00000002
65#define DFA_PIX_24BIT 0x00000004
66#define DFA_PIX_32BIT 0x00000005
67
68
69static const unsigned char pixsize[] = {
70 1, 2, 2, 2, 4, 4
71};
72
73
74#define DTG_CONTROL 0x1900
75#define DTG_CTL_SCREEN_REFRESH 2
76#define DTG_CTL_ENABLE 1
77#define DTG_HORIZ_EXTENT 0x1904
78#define DTG_HORIZ_DISPLAY 0x1908
79#define DTG_HSYNC_START 0x190c
80#define DTG_HSYNC_END 0x1910
81#define DTG_HSYNC_END_COMP 0x1914
82#define DTG_VERT_EXTENT 0x1918
83#define DTG_VERT_DISPLAY 0x191c
84#define DTG_VSYNC_START 0x1920
85#define DTG_VSYNC_END 0x1924
86#define DTG_VERT_SHORT 0x1928
87
88
89#define DISP_CTL 0x402c
90#define DISP_CTL_OFF 2
91#define SYNC_CTL 0x4034
92#define SYNC_CTL_SYNC_ON_RGB 1
93#define SYNC_CTL_SYNC_OFF 2
94#define SYNC_CTL_HSYNC_INV 8
95#define SYNC_CTL_VSYNC_INV 0x10
96#define SYNC_CTL_HSYNC_OFF 0x20
97#define SYNC_CTL_VSYNC_OFF 0x40
98
99#define PLL_M 0x4040
100#define PLL_N 0x4044
101#define PLL_POSTDIV 0x4048
102#define PLL_C 0x404c
103
104
105#define CURSOR_X 0x4078
106#define CURSOR_Y 0x407c
107#define CURSOR_HOTSPOT 0x4080
108#define CURSOR_MODE 0x4084
109#define CURSOR_MODE_OFF 0
110#define CURSOR_MODE_4BPP 1
111#define CURSOR_PIXMAP 0x5000
112#define CURSOR_CMAP 0x7400
113
114
115#define WAT_FMT 0x4100
116#define WAT_FMT_24BIT 0
117#define WAT_FMT_16BIT_565 1
118#define WAT_FMT_16BIT_1555 2
119#define WAT_FMT_32BIT 3
120#define WAT_FMT_8BIT_332 9
121#define WAT_FMT_8BIT 0xa
122#define WAT_FMT_NO_CMAP 4
123#define WAT_CMAP_OFFSET 0x4104
124#define WAT_CTRL 0x4108
125#define WAT_CTRL_SEL_B 1
126#define WAT_CTRL_NO_INC 2
127#define WAT_GAMMA_CTRL 0x410c
128#define WAT_GAMMA_DISABLE 1
129#define WAT_OVL_CTRL 0x430c
130
131
132static const unsigned char watfmt[] = {
133 WAT_FMT_8BIT, WAT_FMT_16BIT_565, WAT_FMT_16BIT_1555, 0,
134 WAT_FMT_24BIT, WAT_FMT_32BIT
135};
136
137
138#define CMAP 0x6000
139
140#define readreg(par, reg) readl((par)->regs + (reg))
141#define writereg(par, reg, val) writel((val), (par)->regs + (reg))
142
143struct gxt4500_par {
144 void __iomem *regs;
145 int wc_cookie;
146 int pixfmt;
147
148
149 int refclk_ps;
150 int pll_m;
151 int pll_n;
152 int pll_pd1;
153 int pll_pd2;
154
155 u32 pseudo_palette[16];
156};
157
158
159static char *mode_option;
160
161
162static const struct fb_videomode defaultmode = {
163 .refresh = 60,
164 .xres = 1280,
165 .yres = 1024,
166 .pixclock = 9295,
167 .left_margin = 248,
168 .right_margin = 48,
169 .upper_margin = 38,
170 .lower_margin = 1,
171 .hsync_len = 112,
172 .vsync_len = 3,
173 .vmode = FB_VMODE_NONINTERLACED
174};
175
176
177enum gxt_cards {
178 GXT4500P,
179 GXT6500P,
180 GXT4000P,
181 GXT6000P
182};
183
184
185static const struct cardinfo {
186 int refclk_ps;
187 const char *cardname;
188} cardinfo[] = {
189 [GXT4500P] = { .refclk_ps = 9259, .cardname = "IBM GXT4500P" },
190 [GXT6500P] = { .refclk_ps = 9259, .cardname = "IBM GXT6500P" },
191 [GXT4000P] = { .refclk_ps = 40000, .cardname = "IBM GXT4000P" },
192 [GXT6000P] = { .refclk_ps = 40000, .cardname = "IBM GXT6000P" },
193};
194
195
196
197
198
199
200
201
202
203
204
205static const unsigned char mdivtab[] = {
206 0x3f, 0x00, 0x20, 0x10, 0x28, 0x14, 0x2a, 0x15, 0x0a,
207 0x25, 0x32, 0x19, 0x0c, 0x26, 0x13, 0x09, 0x04, 0x22, 0x11,
208 0x08, 0x24, 0x12, 0x29, 0x34, 0x1a, 0x2d, 0x36, 0x1b, 0x0d,
209 0x06, 0x23, 0x31, 0x38, 0x1c, 0x2e, 0x17, 0x0b, 0x05, 0x02,
210 0x21, 0x30, 0x18, 0x2c, 0x16, 0x2b, 0x35, 0x3a, 0x1d, 0x0e,
211 0x27, 0x33, 0x39, 0x3c, 0x1e, 0x2f, 0x37, 0x3b, 0x3d, 0x3e,
212 0x1f, 0x0f, 0x07, 0x03, 0x01,
213};
214
215static const unsigned char ndivtab[] = {
216 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0x78, 0xbc, 0x5e,
217 0x2f, 0x17, 0x0b, 0x85, 0xc2, 0xe1, 0x70, 0x38, 0x9c, 0x4e,
218 0xa7, 0xd3, 0xe9, 0xf4, 0xfa, 0xfd, 0xfe, 0x7f, 0xbf, 0xdf,
219 0xef, 0x77, 0x3b, 0x1d, 0x8e, 0xc7, 0xe3, 0x71, 0xb8, 0xdc,
220 0x6e, 0xb7, 0x5b, 0x2d, 0x16, 0x8b, 0xc5, 0xe2, 0xf1, 0xf8,
221 0xfc, 0x7e, 0x3f, 0x9f, 0xcf, 0x67, 0xb3, 0xd9, 0x6c, 0xb6,
222 0xdb, 0x6d, 0x36, 0x9b, 0x4d, 0x26, 0x13, 0x89, 0xc4, 0x62,
223 0xb1, 0xd8, 0xec, 0xf6, 0xfb, 0x7d, 0xbe, 0x5f, 0xaf, 0x57,
224 0x2b, 0x95, 0x4a, 0x25, 0x92, 0x49, 0xa4, 0x52, 0x29, 0x94,
225 0xca, 0x65, 0xb2, 0x59, 0x2c, 0x96, 0xcb, 0xe5, 0xf2, 0x79,
226 0x3c, 0x1e, 0x0f, 0x07, 0x83, 0x41, 0x20, 0x90, 0x48, 0x24,
227 0x12, 0x09, 0x84, 0x42, 0xa1, 0x50, 0x28, 0x14, 0x8a, 0x45,
228 0xa2, 0xd1, 0xe8, 0x74, 0xba, 0xdd, 0xee, 0xf7, 0x7b, 0x3d,
229 0x9e, 0x4f, 0x27, 0x93, 0xc9, 0xe4, 0x72, 0x39, 0x1c, 0x0e,
230 0x87, 0xc3, 0x61, 0x30, 0x18, 0x8c, 0xc6, 0x63, 0x31, 0x98,
231 0xcc, 0xe6, 0x73, 0xb9, 0x5c, 0x2e, 0x97, 0x4b, 0xa5, 0xd2,
232 0x69,
233};
234
235static int calc_pll(int period_ps, struct gxt4500_par *par)
236{
237 int m, n, pdiv1, pdiv2, postdiv;
238 int pll_period, best_error, t, intf;
239
240
241 if (period_ps < 3333 || period_ps > 200000)
242 return -1;
243
244 best_error = 1000000;
245 for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) {
246 for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) {
247 postdiv = pdiv1 * pdiv2;
248 pll_period = DIV_ROUND_UP(period_ps, postdiv);
249
250 if (pll_period < 1666 || pll_period > 2857)
251 continue;
252 for (m = 1; m <= 64; ++m) {
253 intf = m * par->refclk_ps;
254 if (intf > 500000)
255 break;
256 n = intf * postdiv / period_ps;
257 if (n < 3 || n > 160)
258 continue;
259 t = par->refclk_ps * m * postdiv / n;
260 t -= period_ps;
261 if (t >= 0 && t < best_error) {
262 par->pll_m = m;
263 par->pll_n = n;
264 par->pll_pd1 = pdiv1;
265 par->pll_pd2 = pdiv2;
266 best_error = t;
267 }
268 }
269 }
270 }
271 if (best_error == 1000000)
272 return -1;
273 return 0;
274}
275
276static int calc_pixclock(struct gxt4500_par *par)
277{
278 return par->refclk_ps * par->pll_m * par->pll_pd1 * par->pll_pd2
279 / par->pll_n;
280}
281
282static int gxt4500_var_to_par(struct fb_var_screeninfo *var,
283 struct gxt4500_par *par)
284{
285 if (var->xres + var->xoffset > var->xres_virtual ||
286 var->yres + var->yoffset > var->yres_virtual ||
287 var->xres_virtual > 4096)
288 return -EINVAL;
289 if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
290 return -EINVAL;
291
292 if (calc_pll(var->pixclock, par) < 0)
293 return -EINVAL;
294
295 switch (var->bits_per_pixel) {
296 case 32:
297 if (var->transp.length)
298 par->pixfmt = DFA_PIX_32BIT;
299 else
300 par->pixfmt = DFA_PIX_24BIT;
301 break;
302 case 24:
303 par->pixfmt = DFA_PIX_24BIT;
304 break;
305 case 16:
306 if (var->green.length == 5)
307 par->pixfmt = DFA_PIX_16BIT_1555;
308 else
309 par->pixfmt = DFA_PIX_16BIT_565;
310 break;
311 case 8:
312 par->pixfmt = DFA_PIX_8BIT;
313 break;
314 default:
315 return -EINVAL;
316 }
317
318 return 0;
319}
320
321static const struct fb_bitfield eightbits = {0, 8};
322static const struct fb_bitfield nobits = {0, 0};
323
324static void gxt4500_unpack_pixfmt(struct fb_var_screeninfo *var,
325 int pixfmt)
326{
327 var->bits_per_pixel = pixsize[pixfmt] * 8;
328 var->red = eightbits;
329 var->green = eightbits;
330 var->blue = eightbits;
331 var->transp = nobits;
332
333 switch (pixfmt) {
334 case DFA_PIX_16BIT_565:
335 var->red.length = 5;
336 var->green.length = 6;
337 var->blue.length = 5;
338 break;
339 case DFA_PIX_16BIT_1555:
340 var->red.length = 5;
341 var->green.length = 5;
342 var->blue.length = 5;
343 var->transp.length = 1;
344 break;
345 case DFA_PIX_32BIT:
346 var->transp.length = 8;
347 break;
348 }
349 if (pixfmt != DFA_PIX_8BIT) {
350 var->blue.offset = 0;
351 var->green.offset = var->blue.length;
352 var->red.offset = var->green.offset + var->green.length;
353 if (var->transp.length)
354 var->transp.offset =
355 var->red.offset + var->red.length;
356 }
357}
358
359static int gxt4500_check_var(struct fb_var_screeninfo *var,
360 struct fb_info *info)
361{
362 struct gxt4500_par par;
363 int err;
364
365 par = *(struct gxt4500_par *)info->par;
366 err = gxt4500_var_to_par(var, &par);
367 if (!err) {
368 var->pixclock = calc_pixclock(&par);
369 gxt4500_unpack_pixfmt(var, par.pixfmt);
370 }
371 return err;
372}
373
374static int gxt4500_set_par(struct fb_info *info)
375{
376 struct gxt4500_par *par = info->par;
377 struct fb_var_screeninfo *var = &info->var;
378 int err;
379 u32 ctrlreg, tmp;
380 unsigned int dfa_ctl, pixfmt, stride;
381 unsigned int wid_tiles, i;
382 unsigned int prefetch_pix, htot;
383 struct gxt4500_par save_par;
384
385 save_par = *par;
386 err = gxt4500_var_to_par(var, par);
387 if (err) {
388 *par = save_par;
389 return err;
390 }
391
392
393 ctrlreg = readreg(par, DTG_CONTROL);
394 ctrlreg &= ~(DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH);
395 writereg(par, DTG_CONTROL, ctrlreg);
396
397
398 tmp = readreg(par, PLL_C) & ~0x7f;
399 if (par->pll_n < 38)
400 tmp |= 0x29;
401 if (par->pll_n < 69)
402 tmp |= 0x35;
403 else if (par->pll_n < 100)
404 tmp |= 0x76;
405 else
406 tmp |= 0x7e;
407 writereg(par, PLL_C, tmp);
408 writereg(par, PLL_M, mdivtab[par->pll_m - 1]);
409 writereg(par, PLL_N, ndivtab[par->pll_n - 2]);
410 tmp = ((8 - par->pll_pd2) << 3) | (8 - par->pll_pd1);
411 if (par->pll_pd1 == 8 || par->pll_pd2 == 8) {
412
413 writereg(par, PLL_POSTDIV, tmp | 0x9);
414 udelay(1);
415 }
416 writereg(par, PLL_POSTDIV, tmp);
417 msleep(20);
418
419
420 writereg(par, CURSOR_MODE, CURSOR_MODE_OFF);
421
422
423 writereg(par, CTRL_REG0, CR0_RASTER_RESET | (CR0_RASTER_RESET << 16));
424 udelay(10);
425 writereg(par, CTRL_REG0, CR0_RASTER_RESET << 16);
426
427
428 htot = var->xres + var->left_margin + var->right_margin +
429 var->hsync_len;
430 writereg(par, DTG_HORIZ_EXTENT, htot - 1);
431 writereg(par, DTG_HORIZ_DISPLAY, var->xres - 1);
432 writereg(par, DTG_HSYNC_START, var->xres + var->right_margin - 1);
433 writereg(par, DTG_HSYNC_END,
434 var->xres + var->right_margin + var->hsync_len - 1);
435 writereg(par, DTG_HSYNC_END_COMP,
436 var->xres + var->right_margin + var->hsync_len - 1);
437 writereg(par, DTG_VERT_EXTENT,
438 var->yres + var->upper_margin + var->lower_margin +
439 var->vsync_len - 1);
440 writereg(par, DTG_VERT_DISPLAY, var->yres - 1);
441 writereg(par, DTG_VSYNC_START, var->yres + var->lower_margin - 1);
442 writereg(par, DTG_VSYNC_END,
443 var->yres + var->lower_margin + var->vsync_len - 1);
444 prefetch_pix = 3300000 / var->pixclock;
445 if (prefetch_pix >= htot)
446 prefetch_pix = htot - 1;
447 writereg(par, DTG_VERT_SHORT, htot - prefetch_pix - 1);
448 ctrlreg |= DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH;
449 writereg(par, DTG_CONTROL, ctrlreg);
450
451
452 if (var->xres_virtual > 2048) {
453 stride = 4096;
454 dfa_ctl = DFA_FB_STRIDE_4k;
455 } else if (var->xres_virtual > 1024) {
456 stride = 2048;
457 dfa_ctl = DFA_FB_STRIDE_2k;
458 } else {
459 stride = 1024;
460 dfa_ctl = DFA_FB_STRIDE_1k;
461 }
462
463
464 wid_tiles = (var->xres_virtual + 63) >> 6;
465
466
467 writereg(par, FB_AB_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
468 writereg(par, REFRESH_AB_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
469 writereg(par, FB_CD_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
470 writereg(par, REFRESH_CD_CTRL, FB_CTRL_TYPE | (wid_tiles << 16) | 0);
471 writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
472 writereg(par, REFRESH_SIZE, (var->xres << 16) | var->yres);
473
474
475
476 pixfmt = par->pixfmt;
477 dfa_ctl |= DFA_FB_ENABLE | pixfmt;
478 writereg(par, DFA_FB_A, dfa_ctl);
479
480
481
482
483
484
485 for (i = 0; i < 32; ++i) {
486 writereg(par, WAT_FMT + (i << 4), watfmt[pixfmt]);
487 writereg(par, WAT_CMAP_OFFSET + (i << 4), 0);
488 writereg(par, WAT_CTRL + (i << 4), 0);
489 writereg(par, WAT_GAMMA_CTRL + (i << 4), WAT_GAMMA_DISABLE);
490 }
491
492
493 ctrlreg = readreg(par, SYNC_CTL) &
494 ~(SYNC_CTL_SYNC_ON_RGB | SYNC_CTL_HSYNC_INV |
495 SYNC_CTL_VSYNC_INV);
496 if (var->sync & FB_SYNC_ON_GREEN)
497 ctrlreg |= SYNC_CTL_SYNC_ON_RGB;
498 if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
499 ctrlreg |= SYNC_CTL_HSYNC_INV;
500 if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
501 ctrlreg |= SYNC_CTL_VSYNC_INV;
502 writereg(par, SYNC_CTL, ctrlreg);
503
504 info->fix.line_length = stride * pixsize[pixfmt];
505 info->fix.visual = (pixfmt == DFA_PIX_8BIT)? FB_VISUAL_PSEUDOCOLOR:
506 FB_VISUAL_DIRECTCOLOR;
507
508 return 0;
509}
510
511static int gxt4500_setcolreg(unsigned int reg, unsigned int red,
512 unsigned int green, unsigned int blue,
513 unsigned int transp, struct fb_info *info)
514{
515 u32 cmap_entry;
516 struct gxt4500_par *par = info->par;
517
518 if (reg > 1023)
519 return 1;
520 cmap_entry = ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) |
521 (green & 0xff00) | (blue >> 8);
522 writereg(par, CMAP + reg * 4, cmap_entry);
523
524 if (reg < 16 && par->pixfmt != DFA_PIX_8BIT) {
525 u32 *pal = info->pseudo_palette;
526 u32 val = reg;
527 switch (par->pixfmt) {
528 case DFA_PIX_16BIT_565:
529 val |= (reg << 11) | (reg << 5);
530 break;
531 case DFA_PIX_16BIT_1555:
532 val |= (reg << 10) | (reg << 5);
533 break;
534 case DFA_PIX_32BIT:
535 val |= (reg << 24);
536
537 case DFA_PIX_24BIT:
538 val |= (reg << 16) | (reg << 8);
539 break;
540 }
541 pal[reg] = val;
542 }
543
544 return 0;
545}
546
547static int gxt4500_pan_display(struct fb_var_screeninfo *var,
548 struct fb_info *info)
549{
550 struct gxt4500_par *par = info->par;
551
552 if (var->xoffset & 7)
553 return -EINVAL;
554 if (var->xoffset + info->var.xres > info->var.xres_virtual ||
555 var->yoffset + info->var.yres > info->var.yres_virtual)
556 return -EINVAL;
557
558 writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset);
559 return 0;
560}
561
562static int gxt4500_blank(int blank, struct fb_info *info)
563{
564 struct gxt4500_par *par = info->par;
565 int ctrl, dctl;
566
567 ctrl = readreg(par, SYNC_CTL);
568 ctrl &= ~(SYNC_CTL_SYNC_OFF | SYNC_CTL_HSYNC_OFF | SYNC_CTL_VSYNC_OFF);
569 dctl = readreg(par, DISP_CTL);
570 dctl |= DISP_CTL_OFF;
571 switch (blank) {
572 case FB_BLANK_UNBLANK:
573 dctl &= ~DISP_CTL_OFF;
574 break;
575 case FB_BLANK_POWERDOWN:
576 ctrl |= SYNC_CTL_SYNC_OFF;
577 break;
578 case FB_BLANK_HSYNC_SUSPEND:
579 ctrl |= SYNC_CTL_HSYNC_OFF;
580 break;
581 case FB_BLANK_VSYNC_SUSPEND:
582 ctrl |= SYNC_CTL_VSYNC_OFF;
583 break;
584 default: ;
585 }
586 writereg(par, SYNC_CTL, ctrl);
587 writereg(par, DISP_CTL, dctl);
588
589 return 0;
590}
591
592static const struct fb_fix_screeninfo gxt4500_fix = {
593 .id = "IBM GXT4500P",
594 .type = FB_TYPE_PACKED_PIXELS,
595 .visual = FB_VISUAL_PSEUDOCOLOR,
596 .xpanstep = 8,
597 .ypanstep = 1,
598 .mmio_len = 0x20000,
599};
600
601static struct fb_ops gxt4500_ops = {
602 .owner = THIS_MODULE,
603 .fb_check_var = gxt4500_check_var,
604 .fb_set_par = gxt4500_set_par,
605 .fb_setcolreg = gxt4500_setcolreg,
606 .fb_pan_display = gxt4500_pan_display,
607 .fb_blank = gxt4500_blank,
608 .fb_fillrect = cfb_fillrect,
609 .fb_copyarea = cfb_copyarea,
610 .fb_imageblit = cfb_imageblit,
611};
612
613
614static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
615{
616 int err;
617 unsigned long reg_phys, fb_phys;
618 struct gxt4500_par *par;
619 struct fb_info *info;
620 struct fb_var_screeninfo var;
621 enum gxt_cards cardtype;
622
623 err = pci_enable_device(pdev);
624 if (err) {
625 dev_err(&pdev->dev, "gxt4500: cannot enable PCI device: %d\n",
626 err);
627 return err;
628 }
629
630 reg_phys = pci_resource_start(pdev, 0);
631 if (!request_mem_region(reg_phys, pci_resource_len(pdev, 0),
632 "gxt4500 regs")) {
633 dev_err(&pdev->dev, "gxt4500: cannot get registers\n");
634 goto err_nodev;
635 }
636
637 fb_phys = pci_resource_start(pdev, 1);
638 if (!request_mem_region(fb_phys, pci_resource_len(pdev, 1),
639 "gxt4500 FB")) {
640 dev_err(&pdev->dev, "gxt4500: cannot get framebuffer\n");
641 goto err_free_regs;
642 }
643
644 info = framebuffer_alloc(sizeof(struct gxt4500_par), &pdev->dev);
645 if (!info) {
646 dev_err(&pdev->dev, "gxt4500: cannot alloc FB info record\n");
647 goto err_free_fb;
648 }
649 par = info->par;
650 cardtype = ent->driver_data;
651 par->refclk_ps = cardinfo[cardtype].refclk_ps;
652 info->fix = gxt4500_fix;
653 strlcpy(info->fix.id, cardinfo[cardtype].cardname,
654 sizeof(info->fix.id));
655 info->pseudo_palette = par->pseudo_palette;
656
657 info->fix.mmio_start = reg_phys;
658 par->regs = pci_ioremap_bar(pdev, 0);
659 if (!par->regs) {
660 dev_err(&pdev->dev, "gxt4500: cannot map registers\n");
661 goto err_free_all;
662 }
663
664 info->fix.smem_start = fb_phys;
665 info->fix.smem_len = pci_resource_len(pdev, 1);
666 info->screen_base = pci_ioremap_wc_bar(pdev, 1);
667 if (!info->screen_base) {
668 dev_err(&pdev->dev, "gxt4500: cannot map framebuffer\n");
669 goto err_unmap_regs;
670 }
671
672 pci_set_drvdata(pdev, info);
673
674 par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,
675 info->fix.smem_len);
676
677#ifdef __BIG_ENDIAN
678
679 pci_write_config_dword(pdev, CFG_ENDIAN0, 0x333300);
680#else
681
682 pci_write_config_dword(pdev, CFG_ENDIAN0, 0x2300);
683
684 pci_write_config_dword(pdev, CFG_ENDIAN0 + 8, 0x98530000);
685#endif
686
687 info->fbops = &gxt4500_ops;
688 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_XPAN |
689 FBINFO_HWACCEL_YPAN;
690
691 err = fb_alloc_cmap(&info->cmap, 256, 0);
692 if (err) {
693 dev_err(&pdev->dev, "gxt4500: cannot allocate cmap\n");
694 goto err_unmap_all;
695 }
696
697 gxt4500_blank(FB_BLANK_UNBLANK, info);
698
699 if (!fb_find_mode(&var, info, mode_option, NULL, 0, &defaultmode, 8)) {
700 dev_err(&pdev->dev, "gxt4500: cannot find valid video mode\n");
701 goto err_free_cmap;
702 }
703 info->var = var;
704 if (gxt4500_set_par(info)) {
705 printk(KERN_ERR "gxt4500: cannot set video mode\n");
706 goto err_free_cmap;
707 }
708
709 if (register_framebuffer(info) < 0) {
710 dev_err(&pdev->dev, "gxt4500: cannot register framebuffer\n");
711 goto err_free_cmap;
712 }
713 fb_info(info, "%s frame buffer device\n", info->fix.id);
714
715 return 0;
716
717 err_free_cmap:
718 fb_dealloc_cmap(&info->cmap);
719 err_unmap_all:
720 iounmap(info->screen_base);
721 err_unmap_regs:
722 iounmap(par->regs);
723 err_free_all:
724 framebuffer_release(info);
725 err_free_fb:
726 release_mem_region(fb_phys, pci_resource_len(pdev, 1));
727 err_free_regs:
728 release_mem_region(reg_phys, pci_resource_len(pdev, 0));
729 err_nodev:
730 return -ENODEV;
731}
732
733static void gxt4500_remove(struct pci_dev *pdev)
734{
735 struct fb_info *info = pci_get_drvdata(pdev);
736 struct gxt4500_par *par;
737
738 if (!info)
739 return;
740 par = info->par;
741 unregister_framebuffer(info);
742 arch_phys_wc_del(par->wc_cookie);
743 fb_dealloc_cmap(&info->cmap);
744 iounmap(par->regs);
745 iounmap(info->screen_base);
746 release_mem_region(pci_resource_start(pdev, 0),
747 pci_resource_len(pdev, 0));
748 release_mem_region(pci_resource_start(pdev, 1),
749 pci_resource_len(pdev, 1));
750 framebuffer_release(info);
751}
752
753
754static const struct pci_device_id gxt4500_pci_tbl[] = {
755 { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P),
756 .driver_data = GXT4500P },
757 { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6500P),
758 .driver_data = GXT6500P },
759 { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4000P),
760 .driver_data = GXT4000P },
761 { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6000P),
762 .driver_data = GXT6000P },
763 { 0 }
764};
765
766MODULE_DEVICE_TABLE(pci, gxt4500_pci_tbl);
767
768static struct pci_driver gxt4500_driver = {
769 .name = "gxt4500",
770 .id_table = gxt4500_pci_tbl,
771 .probe = gxt4500_probe,
772 .remove = gxt4500_remove,
773};
774
775static int gxt4500_init(void)
776{
777#ifndef MODULE
778 if (fb_get_options("gxt4500", &mode_option))
779 return -ENODEV;
780#endif
781
782 return pci_register_driver(&gxt4500_driver);
783}
784module_init(gxt4500_init);
785
786static void __exit gxt4500_exit(void)
787{
788 pci_unregister_driver(&gxt4500_driver);
789}
790module_exit(gxt4500_exit);
791
792MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
793MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6500P and GXT4000P/6000P");
794MODULE_LICENSE("GPL");
795module_param(mode_option, charp, 0);
796MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");
797