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