blob: f89c3cce1e0c3b1111e9f03c199090ced7434a33 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * SGI GBE frame buffer driver
3 *
4 * Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist
5 * Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.org>
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file COPYING in the main directory of this archive for
9 * more details.
10 */
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/delay.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010013#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/dma-mapping.h>
15#include <linux/errno.h>
16#include <linux/fb.h>
17#include <linux/init.h>
18#include <linux/interrupt.h>
19#include <linux/kernel.h>
20#include <linux/mm.h>
21#include <linux/module.h>
22
23#ifdef CONFIG_X86
24#include <asm/mtrr.h>
25#endif
26#ifdef CONFIG_MIPS
27#include <asm/addrspace.h>
28#endif
29#include <asm/byteorder.h>
30#include <asm/io.h>
31#include <asm/tlbflush.h>
32
33#include <video/gbe.h>
34
35static struct sgi_gbe *gbe;
36
37struct gbefb_par {
38 struct fb_var_screeninfo var;
39 struct gbe_timing_info timing;
40 int valid;
41};
42
43#ifdef CONFIG_SGI_IP32
44#define GBE_BASE 0x16000000 /* SGI O2 */
45#endif
46
47#ifdef CONFIG_X86_VISWS
48#define GBE_BASE 0xd0000000 /* SGI Visual Workstation */
49#endif
50
51/* macro for fastest write-though access to the framebuffer */
52#ifdef CONFIG_MIPS
53#ifdef CONFIG_CPU_R10000
54#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
55#else
56#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
57#endif
58#endif
59#ifdef CONFIG_X86
60#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD)
61#endif
62
63/*
64 * RAM we reserve for the frame buffer. This defines the maximum screen
65 * size
66 */
67#if CONFIG_FB_GBE_MEM > 8
68#error GBE Framebuffer cannot use more than 8MB of memory
69#endif
70
71#define TILE_SHIFT 16
72#define TILE_SIZE (1 << TILE_SHIFT)
73#define TILE_MASK (TILE_SIZE - 1)
74
75static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
76static void *gbe_mem;
77static dma_addr_t gbe_dma_addr;
78unsigned long gbe_mem_phys;
79
80static struct {
81 uint16_t *cpu;
82 dma_addr_t dma;
83} gbe_tiles;
84
85static int gbe_revision;
86
87static int ypan, ywrap;
88
Antonino A. Daplas9058be42007-07-17 04:05:37 -070089static uint32_t pseudo_palette[16];
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -070090static uint32_t gbe_cmap[256];
91static int gbe_turned_on; /* 0 turned off, 1 turned on */
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93static char *mode_option __initdata = NULL;
94
95/* default CRT mode */
96static struct fb_var_screeninfo default_var_CRT __initdata = {
97 /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
98 .xres = 640,
99 .yres = 480,
100 .xres_virtual = 640,
101 .yres_virtual = 480,
102 .xoffset = 0,
103 .yoffset = 0,
104 .bits_per_pixel = 8,
105 .grayscale = 0,
106 .red = { 0, 8, 0 },
107 .green = { 0, 8, 0 },
108 .blue = { 0, 8, 0 },
109 .transp = { 0, 0, 0 },
110 .nonstd = 0,
111 .activate = 0,
112 .height = -1,
113 .width = -1,
114 .accel_flags = 0,
115 .pixclock = 39722, /* picoseconds */
116 .left_margin = 48,
117 .right_margin = 16,
118 .upper_margin = 33,
119 .lower_margin = 10,
120 .hsync_len = 96,
121 .vsync_len = 2,
122 .sync = 0,
123 .vmode = FB_VMODE_NONINTERLACED,
124};
125
126/* default LCD mode */
127static struct fb_var_screeninfo default_var_LCD __initdata = {
128 /* 1600x1024, 8 bpp */
129 .xres = 1600,
130 .yres = 1024,
131 .xres_virtual = 1600,
132 .yres_virtual = 1024,
133 .xoffset = 0,
134 .yoffset = 0,
135 .bits_per_pixel = 8,
136 .grayscale = 0,
137 .red = { 0, 8, 0 },
138 .green = { 0, 8, 0 },
139 .blue = { 0, 8, 0 },
140 .transp = { 0, 0, 0 },
141 .nonstd = 0,
142 .activate = 0,
143 .height = -1,
144 .width = -1,
145 .accel_flags = 0,
146 .pixclock = 9353,
147 .left_margin = 20,
148 .right_margin = 30,
149 .upper_margin = 37,
150 .lower_margin = 3,
151 .hsync_len = 20,
152 .vsync_len = 3,
153 .sync = 0,
154 .vmode = FB_VMODE_NONINTERLACED
155};
156
157/* default modedb mode */
158/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
159static struct fb_videomode default_mode_CRT __initdata = {
160 .refresh = 60,
161 .xres = 640,
162 .yres = 480,
163 .pixclock = 39722,
164 .left_margin = 48,
165 .right_margin = 16,
166 .upper_margin = 33,
167 .lower_margin = 10,
168 .hsync_len = 96,
169 .vsync_len = 2,
170 .sync = 0,
171 .vmode = FB_VMODE_NONINTERLACED,
172};
173/* 1600x1024 SGI flatpanel 1600sw */
174static struct fb_videomode default_mode_LCD __initdata = {
175 /* 1600x1024, 8 bpp */
176 .xres = 1600,
177 .yres = 1024,
178 .pixclock = 9353,
179 .left_margin = 20,
180 .right_margin = 30,
181 .upper_margin = 37,
182 .lower_margin = 3,
183 .hsync_len = 20,
184 .vsync_len = 3,
185 .vmode = FB_VMODE_NONINTERLACED,
186};
187
Randy Dunlap579d6d92007-11-14 17:00:11 -0800188struct fb_videomode *default_mode __initdata = &default_mode_CRT;
189struct fb_var_screeninfo *default_var __initdata = &default_var_CRT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191static int flat_panel_enabled = 0;
192
193static void gbe_reset(void)
194{
195 /* Turn on dotclock PLL */
196 gbe->ctrlstat = 0x300aa000;
197}
198
199
200/*
201 * Function: gbe_turn_off
202 * Parameters: (None)
203 * Description: This should turn off the monitor and gbe. This is used
204 * when switching between the serial console and the graphics
205 * console.
206 */
207
208void gbe_turn_off(void)
209{
210 int i;
211 unsigned int val, x, y, vpixen_off;
212
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700213 gbe_turned_on = 0;
214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 /* check if pixel counter is on */
216 val = gbe->vt_xy;
217 if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
218 return;
219
220 /* turn off DMA */
221 val = gbe->ovr_control;
222 SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
223 gbe->ovr_control = val;
224 udelay(1000);
225 val = gbe->frm_control;
226 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
227 gbe->frm_control = val;
228 udelay(1000);
229 val = gbe->did_control;
230 SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
231 gbe->did_control = val;
232 udelay(1000);
233
234 /* We have to wait through two vertical retrace periods before
235 * the pixel DMA is turned off for sure. */
236 for (i = 0; i < 10000; i++) {
237 val = gbe->frm_inhwctrl;
238 if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
239 udelay(10);
240 } else {
241 val = gbe->ovr_inhwctrl;
242 if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
243 udelay(10);
244 } else {
245 val = gbe->did_inhwctrl;
246 if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
247 udelay(10);
248 } else
249 break;
250 }
251 }
252 }
253 if (i == 10000)
254 printk(KERN_ERR "gbefb: turn off DMA timed out\n");
255
256 /* wait for vpixen_off */
257 val = gbe->vt_vpixen;
258 vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
259
260 for (i = 0; i < 100000; i++) {
261 val = gbe->vt_xy;
262 x = GET_GBE_FIELD(VT_XY, X, val);
263 y = GET_GBE_FIELD(VT_XY, Y, val);
264 if (y < vpixen_off)
265 break;
266 udelay(1);
267 }
268 if (i == 100000)
269 printk(KERN_ERR
270 "gbefb: wait for vpixen_off timed out\n");
271 for (i = 0; i < 10000; i++) {
272 val = gbe->vt_xy;
273 x = GET_GBE_FIELD(VT_XY, X, val);
274 y = GET_GBE_FIELD(VT_XY, Y, val);
275 if (y > vpixen_off)
276 break;
277 udelay(1);
278 }
279 if (i == 10000)
280 printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
281
282 /* turn off pixel counter */
283 val = 0;
284 SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
285 gbe->vt_xy = val;
286 udelay(10000);
287 for (i = 0; i < 10000; i++) {
288 val = gbe->vt_xy;
289 if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
290 udelay(10);
291 else
292 break;
293 }
294 if (i == 10000)
295 printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
296
297 /* turn off dot clock */
298 val = gbe->dotclock;
299 SET_GBE_FIELD(DOTCLK, RUN, val, 0);
300 gbe->dotclock = val;
301 udelay(10000);
302 for (i = 0; i < 10000; i++) {
303 val = gbe->dotclock;
304 if (GET_GBE_FIELD(DOTCLK, RUN, val))
305 udelay(10);
306 else
307 break;
308 }
309 if (i == 10000)
310 printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
311
312 /* reset the frame DMA FIFO */
313 val = gbe->frm_size_tile;
314 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
315 gbe->frm_size_tile = val;
316 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
317 gbe->frm_size_tile = val;
318}
319
320static void gbe_turn_on(void)
321{
322 unsigned int val, i;
323
324 /*
325 * Check if pixel counter is off, for unknown reason this
326 * code hangs Visual Workstations
327 */
328 if (gbe_revision < 2) {
329 val = gbe->vt_xy;
330 if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
331 return;
332 }
333
334 /* turn on dot clock */
335 val = gbe->dotclock;
336 SET_GBE_FIELD(DOTCLK, RUN, val, 1);
337 gbe->dotclock = val;
338 udelay(10000);
339 for (i = 0; i < 10000; i++) {
340 val = gbe->dotclock;
341 if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
342 udelay(10);
343 else
344 break;
345 }
346 if (i == 10000)
347 printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
348
349 /* turn on pixel counter */
350 val = 0;
351 SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
352 gbe->vt_xy = val;
353 udelay(10000);
354 for (i = 0; i < 10000; i++) {
355 val = gbe->vt_xy;
356 if (GET_GBE_FIELD(VT_XY, FREEZE, val))
357 udelay(10);
358 else
359 break;
360 }
361 if (i == 10000)
362 printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
363
364 /* turn on DMA */
365 val = gbe->frm_control;
366 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
367 gbe->frm_control = val;
368 udelay(1000);
369 for (i = 0; i < 10000; i++) {
370 val = gbe->frm_inhwctrl;
371 if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
372 udelay(10);
373 else
374 break;
375 }
376 if (i == 10000)
377 printk(KERN_ERR "gbefb: turn on DMA timed out\n");
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700378
379 gbe_turned_on = 1;
380}
381
382static void gbe_loadcmap(void)
383{
384 int i, j;
385
386 for (i = 0; i < 256; i++) {
387 for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
388 udelay(10);
389 if (j == 1000)
390 printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
391
392 gbe->cmap[i] = gbe_cmap[i];
393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
395
396/*
397 * Blank the display.
398 */
399static int gbefb_blank(int blank, struct fb_info *info)
400{
401 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
402 switch (blank) {
403 case FB_BLANK_UNBLANK: /* unblank */
404 gbe_turn_on();
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700405 gbe_loadcmap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 break;
407
408 case FB_BLANK_NORMAL: /* blank */
409 gbe_turn_off();
410 break;
411
412 default:
413 /* Nothing */
414 break;
415 }
416 return 0;
417}
418
419/*
420 * Setup flatpanel related registers.
421 */
422static void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
423{
424 int fp_wid, fp_hgt, fp_vbs, fp_vbe;
425 u32 outputVal = 0;
426
427 SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
428 (timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
429 SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
430 (timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
431 gbe->vt_flags = outputVal;
432
433 /* Turn on the flat panel */
434 fp_wid = 1600;
435 fp_hgt = 1024;
436 fp_vbs = 0;
437 fp_vbe = 1600;
438 timing->pll_m = 4;
439 timing->pll_n = 1;
440 timing->pll_p = 0;
441
442 outputVal = 0;
443 SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
444 SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
445 gbe->fp_de = outputVal;
446 outputVal = 0;
447 SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
448 gbe->fp_hdrv = outputVal;
449 outputVal = 0;
450 SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
451 SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
452 gbe->fp_vdrv = outputVal;
453}
454
455struct gbe_pll_info {
456 int clock_rate;
457 int fvco_min;
458 int fvco_max;
459};
460
461static struct gbe_pll_info gbe_pll_table[2] = {
462 { 20, 80, 220 },
463 { 27, 80, 220 },
464};
465
466static int compute_gbe_timing(struct fb_var_screeninfo *var,
467 struct gbe_timing_info *timing)
468{
469 int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
470 int pixclock;
471 struct gbe_pll_info *gbe_pll;
472
473 if (gbe_revision < 2)
474 gbe_pll = &gbe_pll_table[0];
475 else
476 gbe_pll = &gbe_pll_table[1];
477
478 /* Determine valid resolution and timing
479 * GBE crystal runs at 20Mhz or 27Mhz
480 * pll_m, pll_n, pll_p define the following frequencies
481 * fvco = pll_m * 20Mhz / pll_n
482 * fout = fvco / (2**pll_p) */
483 best_error = 1000000000;
484 best_n = best_m = best_p = 0;
485 for (pll_p = 0; pll_p < 4; pll_p++)
486 for (pll_m = 1; pll_m < 256; pll_m++)
487 for (pll_n = 1; pll_n < 64; pll_n++) {
488 pixclock = (1000000 / gbe_pll->clock_rate) *
489 (pll_n << pll_p) / pll_m;
490
491 error = var->pixclock - pixclock;
492
493 if (error < 0)
494 error = -error;
495
496 if (error < best_error &&
497 pll_m / pll_n >
498 gbe_pll->fvco_min / gbe_pll->clock_rate &&
499 pll_m / pll_n <
500 gbe_pll->fvco_max / gbe_pll->clock_rate) {
501 best_error = error;
502 best_m = pll_m;
503 best_n = pll_n;
504 best_p = pll_p;
505 }
506 }
507
508 if (!best_n || !best_m)
509 return -EINVAL; /* Resolution to high */
510
511 pixclock = (1000000 / gbe_pll->clock_rate) *
512 (best_n << best_p) / best_m;
513
514 /* set video timing information */
515 if (timing) {
516 timing->width = var->xres;
517 timing->height = var->yres;
518 timing->pll_m = best_m;
519 timing->pll_n = best_n;
520 timing->pll_p = best_p;
521 timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
522 (timing->pll_n << timing->pll_p);
523 timing->htotal = var->left_margin + var->xres +
524 var->right_margin + var->hsync_len;
525 timing->vtotal = var->upper_margin + var->yres +
526 var->lower_margin + var->vsync_len;
527 timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
528 1000 / timing->vtotal;
529 timing->hblank_start = var->xres;
530 timing->vblank_start = var->yres;
531 timing->hblank_end = timing->htotal;
532 timing->hsync_start = var->xres + var->right_margin + 1;
533 timing->hsync_end = timing->hsync_start + var->hsync_len;
534 timing->vblank_end = timing->vtotal;
535 timing->vsync_start = var->yres + var->lower_margin + 1;
536 timing->vsync_end = timing->vsync_start + var->vsync_len;
537 }
538
539 return pixclock;
540}
541
542static void gbe_set_timing_info(struct gbe_timing_info *timing)
543{
544 int temp;
545 unsigned int val;
546
547 /* setup dot clock PLL */
548 val = 0;
549 SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
550 SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
551 SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
552 SET_GBE_FIELD(DOTCLK, RUN, val, 0); /* do not start yet */
553 gbe->dotclock = val;
554 udelay(10000);
555
556 /* setup pixel counter */
557 val = 0;
558 SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
559 SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
560 gbe->vt_xymax = val;
561
562 /* setup video timing signals */
563 val = 0;
564 SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
565 SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
566 gbe->vt_vsync = val;
567 val = 0;
568 SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
569 SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
570 gbe->vt_hsync = val;
571 val = 0;
572 SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
573 SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
574 gbe->vt_vblank = val;
575 val = 0;
576 SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
577 timing->hblank_start - 5);
578 SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
579 timing->hblank_end - 3);
580 gbe->vt_hblank = val;
581
582 /* setup internal timing signals */
583 val = 0;
584 SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
585 SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
586 gbe->vt_vcmap = val;
587 val = 0;
588 SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
589 SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
590 gbe->vt_hcmap = val;
591
592 val = 0;
593 temp = timing->vblank_start - timing->vblank_end - 1;
594 if (temp > 0)
595 temp = -temp;
596
597 if (flat_panel_enabled)
598 gbefb_setup_flatpanel(timing);
599
600 SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
601 if (timing->hblank_end >= 20)
602 SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
603 timing->hblank_end - 20);
604 else
605 SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
606 timing->htotal - (20 - timing->hblank_end));
607 gbe->did_start_xy = val;
608
609 val = 0;
610 SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
611 if (timing->hblank_end >= GBE_CRS_MAGIC)
612 SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
613 timing->hblank_end - GBE_CRS_MAGIC);
614 else
615 SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
616 timing->htotal - (GBE_CRS_MAGIC -
617 timing->hblank_end));
618 gbe->crs_start_xy = val;
619
620 val = 0;
621 SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
622 SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
623 gbe->vc_start_xy = val;
624
625 val = 0;
626 temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
627 if (temp < 0)
628 temp += timing->htotal; /* allow blank to wrap around */
629
630 SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
631 SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
632 ((temp + timing->width -
633 GBE_PIXEN_MAGIC_OFF) % timing->htotal));
634 gbe->vt_hpixen = val;
635
636 val = 0;
637 SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
638 SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
639 gbe->vt_vpixen = val;
640
641 /* turn off sync on green */
642 val = 0;
643 SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
644 gbe->vt_flags = val;
645}
646
647/*
648 * Set the hardware according to 'par'.
649 */
650
651static int gbefb_set_par(struct fb_info *info)
652{
653 int i;
654 unsigned int val;
655 int wholeTilesX, partTilesX, maxPixelsPerTileX;
656 int height_pix;
657 int xpmax, ypmax; /* Monitor resolution */
658 int bytesPerPixel; /* Bytes per pixel */
659 struct gbefb_par *par = (struct gbefb_par *) info->par;
660
661 compute_gbe_timing(&info->var, &par->timing);
662
663 bytesPerPixel = info->var.bits_per_pixel / 8;
664 info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
665 xpmax = par->timing.width;
666 ypmax = par->timing.height;
667
668 /* turn off GBE */
669 gbe_turn_off();
670
671 /* set timing info */
672 gbe_set_timing_info(&par->timing);
673
674 /* initialize DIDs */
675 val = 0;
676 switch (bytesPerPixel) {
677 case 1:
678 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800679 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 break;
681 case 2:
682 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800683 info->fix.visual = FB_VISUAL_TRUECOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 break;
685 case 4:
686 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800687 info->fix.visual = FB_VISUAL_TRUECOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 break;
689 }
690 SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
691
692 for (i = 0; i < 32; i++)
693 gbe->mode_regs[i] = val;
694
695 /* Initialize interrupts */
696 gbe->vt_intr01 = 0xffffffff;
697 gbe->vt_intr23 = 0xffffffff;
698
699 /* HACK:
700 The GBE hardware uses a tiled memory to screen mapping. Tiles are
701 blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
702 16bit and 32 bit modes (64 kB). They cover the screen with partial
703 tiles on the right and/or bottom of the screen if needed.
704 For exemple in 640x480 8 bit mode the mapping is:
705
706 <-------- 640 ----->
707 <---- 512 ----><128|384 offscreen>
708 ^ ^
709 | 128 [tile 0] [tile 1]
710 | v
711 ^
712 4 128 [tile 2] [tile 3]
713 8 v
714 0 ^
715 128 [tile 4] [tile 5]
716 | v
717 | ^
718 v 96 [tile 6] [tile 7]
719 32 offscreen
720
721 Tiles have the advantage that they can be allocated individually in
722 memory. However, this mapping is not linear at all, which is not
723 really convienient. In order to support linear addressing, the GBE
724 DMA hardware is fooled into thinking the screen is only one tile
725 large and but has a greater height, so that the DMA transfer covers
726 the same region.
727 Tiles are still allocated as independent chunks of 64KB of
728 continuous physical memory and remapped so that the kernel sees the
729 framebuffer as a continuous virtual memory. The GBE tile table is
730 set up so that each tile references one of these 64k blocks:
731
732 GBE -> tile list framebuffer TLB <------------ CPU
733 [ tile 0 ] -> [ 64KB ] <- [ 16x 4KB page entries ] ^
734 ... ... ... linear virtual FB
735 [ tile n ] -> [ 64KB ] <- [ 16x 4KB page entries ] v
736
737
738 The GBE hardware is then told that the buffer is 512*tweaked_height,
739 with tweaked_height = real_width*real_height/pixels_per_tile.
740 Thus the GBE hardware will scan the first tile, filing the first 64k
741 covered region of the screen, and then will proceed to the next
742 tile, until the whole screen is covered.
743
744 Here is what would happen at 640x480 8bit:
745
746 normal tiling linear
747 ^ 11111111111111112222 11111111111111111111 ^
748 128 11111111111111112222 11111111111111111111 102 lines
749 11111111111111112222 11111111111111111111 v
750 V 11111111111111112222 11111111222222222222
751 33333333333333334444 22222222222222222222
752 33333333333333334444 22222222222222222222
753 < 512 > < 256 > 102*640+256 = 64k
754
755 NOTE: The only mode for which this is not working is 800x600 8bit,
756 as 800*600/512 = 937.5 which is not integer and thus causes
757 flickering.
758 I guess this is not so important as one can use 640x480 8bit or
759 800x600 16bit anyway.
760 */
761
762 /* Tell gbe about the tiles table location */
763 /* tile_ptr -> [ tile 1 ] -> FB mem */
764 /* [ tile 2 ] -> FB mem */
765 /* ... */
766 val = 0;
767 SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
768 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
769 SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
770 gbe->frm_control = val;
771
772 maxPixelsPerTileX = 512 / bytesPerPixel;
773 wholeTilesX = 1;
774 partTilesX = 0;
775
776 /* Initialize the framebuffer */
777 val = 0;
778 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
779 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
780
781 switch (bytesPerPixel) {
782 case 1:
783 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
784 GBE_FRM_DEPTH_8);
785 break;
786 case 2:
787 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
788 GBE_FRM_DEPTH_16);
789 break;
790 case 4:
791 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
792 GBE_FRM_DEPTH_32);
793 break;
794 }
795 gbe->frm_size_tile = val;
796
797 /* compute tweaked height */
798 height_pix = xpmax * ypmax / maxPixelsPerTileX;
799
800 val = 0;
801 SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
802 gbe->frm_size_pixel = val;
803
804 /* turn off DID and overlay DMA */
805 gbe->did_control = 0;
806 gbe->ovr_width_tile = 0;
807
808 /* Turn off mouse cursor */
809 gbe->crs_ctl = 0;
810
811 /* Turn on GBE */
812 gbe_turn_on();
813
814 /* Initialize the gamma map */
815 udelay(10);
816 for (i = 0; i < 256; i++)
817 gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
818
819 /* Initialize the color map */
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700820 for (i = 0; i < 256; i++)
821 gbe_cmap[i] = (i << 8) | (i << 16) | (i << 24);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700823 gbe_loadcmap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 return 0;
826}
827
828static void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
829 struct fb_var_screeninfo *var)
830{
831 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
832 strcpy(fix->id, "SGI GBE");
833 fix->smem_start = (unsigned long) gbe_mem;
834 fix->smem_len = gbe_mem_size;
835 fix->type = FB_TYPE_PACKED_PIXELS;
836 fix->type_aux = 0;
837 fix->accel = FB_ACCEL_NONE;
838 switch (var->bits_per_pixel) {
839 case 8:
840 fix->visual = FB_VISUAL_PSEUDOCOLOR;
841 break;
842 default:
843 fix->visual = FB_VISUAL_TRUECOLOR;
844 break;
845 }
846 fix->ywrapstep = 0;
847 fix->xpanstep = 0;
848 fix->ypanstep = 0;
849 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
850 fix->mmio_start = GBE_BASE;
851 fix->mmio_len = sizeof(struct sgi_gbe);
852}
853
854/*
855 * Set a single color register. The values supplied are already
856 * rounded down to the hardware's capabilities (according to the
857 * entries in the var structure). Return != 0 for invalid regno.
858 */
859
860static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
861 unsigned blue, unsigned transp,
862 struct fb_info *info)
863{
864 int i;
865
866 if (regno > 255)
867 return 1;
868 red >>= 8;
869 green >>= 8;
870 blue >>= 8;
871
Antonino A. Daplas9058be42007-07-17 04:05:37 -0700872 if (info->var.bits_per_pixel <= 8) {
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700873 gbe_cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
874 if (gbe_turned_on) {
875 /* wait for the color map FIFO to have a free entry */
876 for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
877 udelay(10);
878 if (i == 1000) {
879 printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
880 return 1;
881 }
882 gbe->cmap[regno] = gbe_cmap[regno];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 }
Antonino A. Daplas9058be42007-07-17 04:05:37 -0700884 } else if (regno < 16) {
885 switch (info->var.bits_per_pixel) {
886 case 15:
887 case 16:
888 red >>= 3;
889 green >>= 3;
890 blue >>= 3;
891 pseudo_palette[regno] =
892 (red << info->var.red.offset) |
893 (green << info->var.green.offset) |
894 (blue << info->var.blue.offset);
895 break;
896 case 32:
897 pseudo_palette[regno] =
898 (red << info->var.red.offset) |
899 (green << info->var.green.offset) |
900 (blue << info->var.blue.offset);
901 break;
902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
904
905 return 0;
906}
907
908/*
909 * Check video mode validity, eventually modify var to best match.
910 */
911static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
912{
913 unsigned int line_length;
914 struct gbe_timing_info timing;
915
916 /* Limit bpp to 8, 16, and 32 */
917 if (var->bits_per_pixel <= 8)
918 var->bits_per_pixel = 8;
919 else if (var->bits_per_pixel <= 16)
920 var->bits_per_pixel = 16;
921 else if (var->bits_per_pixel <= 32)
922 var->bits_per_pixel = 32;
923 else
924 return -EINVAL;
925
926 /* Check the mode can be mapped linearly with the tile table trick. */
927 /* This requires width x height x bytes/pixel be a multiple of 512 */
928 if ((var->xres * var->yres * var->bits_per_pixel) & 4095)
929 return -EINVAL;
930
931 var->grayscale = 0; /* No grayscale for now */
932
933 if ((var->pixclock = compute_gbe_timing(var, &timing)) < 0)
934 return(-EINVAL);
935
936 /* Adjust virtual resolution, if necessary */
937 if (var->xres > var->xres_virtual || (!ywrap && !ypan))
938 var->xres_virtual = var->xres;
939 if (var->yres > var->yres_virtual || (!ywrap && !ypan))
940 var->yres_virtual = var->yres;
941
942 if (var->vmode & FB_VMODE_CONUPDATE) {
943 var->vmode |= FB_VMODE_YWRAP;
944 var->xoffset = info->var.xoffset;
945 var->yoffset = info->var.yoffset;
946 }
947
948 /* No grayscale for now */
949 var->grayscale = 0;
950
951 /* Memory limit */
952 line_length = var->xres_virtual * var->bits_per_pixel / 8;
953 if (line_length * var->yres_virtual > gbe_mem_size)
954 return -ENOMEM; /* Virtual resolution too high */
955
956 switch (var->bits_per_pixel) {
957 case 8:
958 var->red.offset = 0;
959 var->red.length = 8;
960 var->green.offset = 0;
961 var->green.length = 8;
962 var->blue.offset = 0;
963 var->blue.length = 8;
964 var->transp.offset = 0;
965 var->transp.length = 0;
966 break;
967 case 16: /* RGB 1555 */
968 var->red.offset = 10;
969 var->red.length = 5;
970 var->green.offset = 5;
971 var->green.length = 5;
972 var->blue.offset = 0;
973 var->blue.length = 5;
974 var->transp.offset = 0;
975 var->transp.length = 0;
976 break;
977 case 32: /* RGB 8888 */
978 var->red.offset = 24;
979 var->red.length = 8;
980 var->green.offset = 16;
981 var->green.length = 8;
982 var->blue.offset = 8;
983 var->blue.length = 8;
984 var->transp.offset = 0;
985 var->transp.length = 8;
986 break;
987 }
988 var->red.msb_right = 0;
989 var->green.msb_right = 0;
990 var->blue.msb_right = 0;
991 var->transp.msb_right = 0;
992
993 var->left_margin = timing.htotal - timing.hsync_end;
994 var->right_margin = timing.hsync_start - timing.width;
995 var->upper_margin = timing.vtotal - timing.vsync_end;
996 var->lower_margin = timing.vsync_start - timing.height;
997 var->hsync_len = timing.hsync_end - timing.hsync_start;
998 var->vsync_len = timing.vsync_end - timing.vsync_start;
999
1000 return 0;
1001}
1002
Christoph Hellwig216d5262006-01-14 13:21:25 -08001003static int gbefb_mmap(struct fb_info *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 struct vm_area_struct *vma)
1005{
1006 unsigned long size = vma->vm_end - vma->vm_start;
1007 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
1008 unsigned long addr;
1009 unsigned long phys_addr, phys_size;
1010 u16 *tile;
1011
1012 /* check range */
1013 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1014 return -EINVAL;
1015 if (offset + size > gbe_mem_size)
1016 return -EINVAL;
1017
1018 /* remap using the fastest write-through mode on architecture */
1019 /* try not polluting the cache when possible */
1020 pgprot_val(vma->vm_page_prot) =
1021 pgprot_fb(pgprot_val(vma->vm_page_prot));
1022
1023 vma->vm_flags |= VM_IO | VM_RESERVED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 /* look for the starting tile */
1026 tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
1027 addr = vma->vm_start;
1028 offset &= TILE_MASK;
1029
1030 /* remap each tile separately */
1031 do {
1032 phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;
1033 if ((offset + size) < TILE_SIZE)
1034 phys_size = size;
1035 else
1036 phys_size = TILE_SIZE - offset;
1037
1038 if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,
1039 phys_size, vma->vm_page_prot))
1040 return -EAGAIN;
1041
1042 offset = 0;
1043 size -= phys_size;
1044 addr += phys_size;
1045 tile++;
1046 } while (size);
1047
1048 return 0;
1049}
1050
1051static struct fb_ops gbefb_ops = {
1052 .owner = THIS_MODULE,
1053 .fb_check_var = gbefb_check_var,
1054 .fb_set_par = gbefb_set_par,
1055 .fb_setcolreg = gbefb_setcolreg,
1056 .fb_mmap = gbefb_mmap,
1057 .fb_blank = gbefb_blank,
1058 .fb_fillrect = cfb_fillrect,
1059 .fb_copyarea = cfb_copyarea,
1060 .fb_imageblit = cfb_imageblit,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061};
1062
1063/*
1064 * sysfs
1065 */
1066
Yani Ioannou060b8842005-05-17 06:44:04 -04001067static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
1069 return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size);
1070}
1071
1072static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
1073
Yani Ioannou060b8842005-05-17 06:44:04 -04001074static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
1076 return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision);
1077}
1078
1079static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
1080
1081static void __devexit gbefb_remove_sysfs(struct device *dev)
1082{
1083 device_remove_file(dev, &dev_attr_size);
1084 device_remove_file(dev, &dev_attr_revision);
1085}
1086
1087static void gbefb_create_sysfs(struct device *dev)
1088{
1089 device_create_file(dev, &dev_attr_size);
1090 device_create_file(dev, &dev_attr_revision);
1091}
1092
1093/*
1094 * Initialization
1095 */
1096
1097int __init gbefb_setup(char *options)
1098{
1099 char *this_opt;
1100
1101 if (!options || !*options)
1102 return 0;
1103
1104 while ((this_opt = strsep(&options, ",")) != NULL) {
1105 if (!strncmp(this_opt, "monitor:", 8)) {
1106 if (!strncmp(this_opt + 8, "crt", 3)) {
1107 flat_panel_enabled = 0;
1108 default_var = &default_var_CRT;
1109 default_mode = &default_mode_CRT;
1110 } else if (!strncmp(this_opt + 8, "1600sw", 6) ||
1111 !strncmp(this_opt + 8, "lcd", 3)) {
1112 flat_panel_enabled = 1;
1113 default_var = &default_var_LCD;
1114 default_mode = &default_mode_LCD;
1115 }
1116 } else if (!strncmp(this_opt, "mem:", 4)) {
1117 gbe_mem_size = memparse(this_opt + 4, &this_opt);
1118 if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)
1119 gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;
1120 if (gbe_mem_size < TILE_SIZE)
1121 gbe_mem_size = TILE_SIZE;
1122 } else
1123 mode_option = this_opt;
1124 }
1125 return 0;
1126}
1127
Russell King3ae5eae2005-11-09 22:32:44 +00001128static int __init gbefb_probe(struct platform_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129{
1130 int i, ret = 0;
1131 struct fb_info *info;
1132 struct gbefb_par *par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133#ifndef MODULE
1134 char *options = NULL;
1135#endif
1136
1137 info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev);
1138 if (!info)
1139 return -ENOMEM;
1140
1141#ifndef MODULE
1142 if (fb_get_options("gbefb", &options))
1143 return -ENODEV;
1144 gbefb_setup(options);
1145#endif
1146
Thiemo Seufer6d7bf012005-03-04 19:40:45 +00001147 if (!request_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
1149 ret = -EBUSY;
1150 goto out_release_framebuffer;
1151 }
1152
1153 gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe));
1154 if (!gbe) {
1155 printk(KERN_ERR "gbefb: couldn't map mmio region\n");
1156 ret = -ENXIO;
1157 goto out_release_mem_region;
1158 }
1159 gbe_revision = gbe->ctrlstat & 15;
1160
1161 gbe_tiles.cpu =
1162 dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
1163 &gbe_tiles.dma, GFP_KERNEL);
1164 if (!gbe_tiles.cpu) {
1165 printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
1166 ret = -ENOMEM;
1167 goto out_unmap;
1168 }
1169
1170 if (gbe_mem_phys) {
1171 /* memory was allocated at boot time */
1172 gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size);
Thiemo Seufer6d7bf012005-03-04 19:40:45 +00001173 if (!gbe_mem) {
1174 printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
1175 ret = -ENOMEM;
1176 goto out_tiles_free;
1177 }
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 gbe_dma_addr = 0;
1180 } else {
1181 /* try to allocate memory with the classical allocator
1182 * this has high chance to fail on low memory machines */
1183 gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr,
1184 GFP_KERNEL);
Thiemo Seufer6d7bf012005-03-04 19:40:45 +00001185 if (!gbe_mem) {
1186 printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n");
1187 ret = -ENOMEM;
1188 goto out_tiles_free;
1189 }
1190
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 gbe_mem_phys = (unsigned long) gbe_dma_addr;
1192 }
1193
1194#ifdef CONFIG_X86
1195 mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);
1196#endif
1197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 /* map framebuffer memory into tiles table */
1199 for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
1200 gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
1201
1202 info->fbops = &gbefb_ops;
1203 info->pseudo_palette = pseudo_palette;
1204 info->flags = FBINFO_DEFAULT;
1205 info->screen_base = gbe_mem;
1206 fb_alloc_cmap(&info->cmap, 256, 0);
1207
1208 /* reset GBE */
1209 gbe_reset();
1210
1211 par = info->par;
1212 /* turn on default video mode */
1213 if (fb_find_mode(&par->var, info, mode_option, NULL, 0,
1214 default_mode, 8) == 0)
1215 par->var = *default_var;
1216 info->var = par->var;
1217 gbefb_check_var(&par->var, info);
1218 gbefb_encode_fix(&info->fix, &info->var);
1219
1220 if (register_framebuffer(info) < 0) {
1221 printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
1222 ret = -ENXIO;
1223 goto out_gbe_unmap;
1224 }
1225
Russell King3ae5eae2005-11-09 22:32:44 +00001226 platform_set_drvdata(p_dev, info);
1227 gbefb_create_sysfs(&p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
1229 printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n",
1230 info->node, info->fix.id, gbe_revision, (unsigned) GBE_BASE,
1231 gbe_mem_size >> 10);
1232
1233 return 0;
1234
1235out_gbe_unmap:
1236 if (gbe_dma_addr)
1237 dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
1238 else
1239 iounmap(gbe_mem);
1240out_tiles_free:
1241 dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
1242 (void *)gbe_tiles.cpu, gbe_tiles.dma);
1243out_unmap:
1244 iounmap(gbe);
1245out_release_mem_region:
1246 release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
1247out_release_framebuffer:
1248 framebuffer_release(info);
1249
1250 return ret;
1251}
1252
Russell King3ae5eae2005-11-09 22:32:44 +00001253static int __devexit gbefb_remove(struct platform_device* p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254{
Russell King3ae5eae2005-11-09 22:32:44 +00001255 struct fb_info *info = platform_get_drvdata(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 unregister_framebuffer(info);
1258 gbe_turn_off();
1259 if (gbe_dma_addr)
1260 dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
1261 else
1262 iounmap(gbe_mem);
1263 dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
1264 (void *)gbe_tiles.cpu, gbe_tiles.dma);
1265 release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
1266 iounmap(gbe);
Joshua Kinardd3086432006-02-17 03:52:25 +00001267 gbefb_remove_sysfs(&p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 framebuffer_release(info);
1269
1270 return 0;
1271}
1272
Russell King3ae5eae2005-11-09 22:32:44 +00001273static struct platform_driver gbefb_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 .probe = gbefb_probe,
1275 .remove = __devexit_p(gbefb_remove),
Russell King3ae5eae2005-11-09 22:32:44 +00001276 .driver = {
1277 .name = "gbefb",
1278 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279};
1280
Russell Kingabbf2682005-11-05 21:22:13 +00001281static struct platform_device *gbefb_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
1283int __init gbefb_init(void)
1284{
Russell King3ae5eae2005-11-09 22:32:44 +00001285 int ret = platform_driver_register(&gbefb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (!ret) {
Russell Kingabbf2682005-11-05 21:22:13 +00001287 gbefb_device = platform_device_alloc("gbefb", 0);
1288 if (gbefb_device) {
1289 ret = platform_device_add(gbefb_device);
1290 } else {
1291 ret = -ENOMEM;
1292 }
1293 if (ret) {
1294 platform_device_put(gbefb_device);
Russell King3ae5eae2005-11-09 22:32:44 +00001295 platform_driver_unregister(&gbefb_driver);
Russell Kingabbf2682005-11-05 21:22:13 +00001296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 }
1298 return ret;
1299}
1300
1301void __exit gbefb_exit(void)
1302{
Russell Kingabbf2682005-11-05 21:22:13 +00001303 platform_device_unregister(gbefb_device);
Russell King3ae5eae2005-11-09 22:32:44 +00001304 platform_driver_unregister(&gbefb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305}
1306
1307module_init(gbefb_init);
1308module_exit(gbefb_exit);
1309
1310MODULE_LICENSE("GPL");