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