blob: 5e25b98601967722df5e6014fbfb35d97abedcb7 [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
12#include <linux/config.h>
13#include <linux/delay.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010014#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/dma-mapping.h>
16#include <linux/errno.h>
17#include <linux/fb.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/kernel.h>
21#include <linux/mm.h>
22#include <linux/module.h>
23
24#ifdef CONFIG_X86
25#include <asm/mtrr.h>
26#endif
27#ifdef CONFIG_MIPS
28#include <asm/addrspace.h>
29#endif
30#include <asm/byteorder.h>
31#include <asm/io.h>
32#include <asm/tlbflush.h>
33
34#include <video/gbe.h>
35
36static struct sgi_gbe *gbe;
37
38struct gbefb_par {
39 struct fb_var_screeninfo var;
40 struct gbe_timing_info timing;
41 int valid;
42};
43
44#ifdef CONFIG_SGI_IP32
45#define GBE_BASE 0x16000000 /* SGI O2 */
46#endif
47
48#ifdef CONFIG_X86_VISWS
49#define GBE_BASE 0xd0000000 /* SGI Visual Workstation */
50#endif
51
52/* macro for fastest write-though access to the framebuffer */
53#ifdef CONFIG_MIPS
54#ifdef CONFIG_CPU_R10000
55#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
56#else
57#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
58#endif
59#endif
60#ifdef CONFIG_X86
61#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD)
62#endif
63
64/*
65 * RAM we reserve for the frame buffer. This defines the maximum screen
66 * size
67 */
68#if CONFIG_FB_GBE_MEM > 8
69#error GBE Framebuffer cannot use more than 8MB of memory
70#endif
71
72#define TILE_SHIFT 16
73#define TILE_SIZE (1 << TILE_SHIFT)
74#define TILE_MASK (TILE_SIZE - 1)
75
76static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
77static void *gbe_mem;
78static dma_addr_t gbe_dma_addr;
79unsigned long gbe_mem_phys;
80
81static struct {
82 uint16_t *cpu;
83 dma_addr_t dma;
84} gbe_tiles;
85
86static int gbe_revision;
87
88static int ypan, ywrap;
89
90static uint32_t pseudo_palette[256];
91
92static char *mode_option __initdata = NULL;
93
94/* default CRT mode */
95static struct fb_var_screeninfo default_var_CRT __initdata = {
96 /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
97 .xres = 640,
98 .yres = 480,
99 .xres_virtual = 640,
100 .yres_virtual = 480,
101 .xoffset = 0,
102 .yoffset = 0,
103 .bits_per_pixel = 8,
104 .grayscale = 0,
105 .red = { 0, 8, 0 },
106 .green = { 0, 8, 0 },
107 .blue = { 0, 8, 0 },
108 .transp = { 0, 0, 0 },
109 .nonstd = 0,
110 .activate = 0,
111 .height = -1,
112 .width = -1,
113 .accel_flags = 0,
114 .pixclock = 39722, /* picoseconds */
115 .left_margin = 48,
116 .right_margin = 16,
117 .upper_margin = 33,
118 .lower_margin = 10,
119 .hsync_len = 96,
120 .vsync_len = 2,
121 .sync = 0,
122 .vmode = FB_VMODE_NONINTERLACED,
123};
124
125/* default LCD mode */
126static struct fb_var_screeninfo default_var_LCD __initdata = {
127 /* 1600x1024, 8 bpp */
128 .xres = 1600,
129 .yres = 1024,
130 .xres_virtual = 1600,
131 .yres_virtual = 1024,
132 .xoffset = 0,
133 .yoffset = 0,
134 .bits_per_pixel = 8,
135 .grayscale = 0,
136 .red = { 0, 8, 0 },
137 .green = { 0, 8, 0 },
138 .blue = { 0, 8, 0 },
139 .transp = { 0, 0, 0 },
140 .nonstd = 0,
141 .activate = 0,
142 .height = -1,
143 .width = -1,
144 .accel_flags = 0,
145 .pixclock = 9353,
146 .left_margin = 20,
147 .right_margin = 30,
148 .upper_margin = 37,
149 .lower_margin = 3,
150 .hsync_len = 20,
151 .vsync_len = 3,
152 .sync = 0,
153 .vmode = FB_VMODE_NONINTERLACED
154};
155
156/* default modedb mode */
157/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
158static struct fb_videomode default_mode_CRT __initdata = {
159 .refresh = 60,
160 .xres = 640,
161 .yres = 480,
162 .pixclock = 39722,
163 .left_margin = 48,
164 .right_margin = 16,
165 .upper_margin = 33,
166 .lower_margin = 10,
167 .hsync_len = 96,
168 .vsync_len = 2,
169 .sync = 0,
170 .vmode = FB_VMODE_NONINTERLACED,
171};
172/* 1600x1024 SGI flatpanel 1600sw */
173static struct fb_videomode default_mode_LCD __initdata = {
174 /* 1600x1024, 8 bpp */
175 .xres = 1600,
176 .yres = 1024,
177 .pixclock = 9353,
178 .left_margin = 20,
179 .right_margin = 30,
180 .upper_margin = 37,
181 .lower_margin = 3,
182 .hsync_len = 20,
183 .vsync_len = 3,
184 .vmode = FB_VMODE_NONINTERLACED,
185};
186
187struct fb_videomode *default_mode = &default_mode_CRT;
188struct fb_var_screeninfo *default_var = &default_var_CRT;
189
190static int flat_panel_enabled = 0;
191
192static void gbe_reset(void)
193{
194 /* Turn on dotclock PLL */
195 gbe->ctrlstat = 0x300aa000;
196}
197
198
199/*
200 * Function: gbe_turn_off
201 * Parameters: (None)
202 * Description: This should turn off the monitor and gbe. This is used
203 * when switching between the serial console and the graphics
204 * console.
205 */
206
207void gbe_turn_off(void)
208{
209 int i;
210 unsigned int val, x, y, vpixen_off;
211
212 /* check if pixel counter is on */
213 val = gbe->vt_xy;
214 if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
215 return;
216
217 /* turn off DMA */
218 val = gbe->ovr_control;
219 SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
220 gbe->ovr_control = val;
221 udelay(1000);
222 val = gbe->frm_control;
223 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
224 gbe->frm_control = val;
225 udelay(1000);
226 val = gbe->did_control;
227 SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
228 gbe->did_control = val;
229 udelay(1000);
230
231 /* We have to wait through two vertical retrace periods before
232 * the pixel DMA is turned off for sure. */
233 for (i = 0; i < 10000; i++) {
234 val = gbe->frm_inhwctrl;
235 if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
236 udelay(10);
237 } else {
238 val = gbe->ovr_inhwctrl;
239 if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
240 udelay(10);
241 } else {
242 val = gbe->did_inhwctrl;
243 if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
244 udelay(10);
245 } else
246 break;
247 }
248 }
249 }
250 if (i == 10000)
251 printk(KERN_ERR "gbefb: turn off DMA timed out\n");
252
253 /* wait for vpixen_off */
254 val = gbe->vt_vpixen;
255 vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
256
257 for (i = 0; i < 100000; i++) {
258 val = gbe->vt_xy;
259 x = GET_GBE_FIELD(VT_XY, X, val);
260 y = GET_GBE_FIELD(VT_XY, Y, val);
261 if (y < vpixen_off)
262 break;
263 udelay(1);
264 }
265 if (i == 100000)
266 printk(KERN_ERR
267 "gbefb: wait for vpixen_off timed out\n");
268 for (i = 0; i < 10000; i++) {
269 val = gbe->vt_xy;
270 x = GET_GBE_FIELD(VT_XY, X, val);
271 y = GET_GBE_FIELD(VT_XY, Y, val);
272 if (y > vpixen_off)
273 break;
274 udelay(1);
275 }
276 if (i == 10000)
277 printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
278
279 /* turn off pixel counter */
280 val = 0;
281 SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
282 gbe->vt_xy = val;
283 udelay(10000);
284 for (i = 0; i < 10000; i++) {
285 val = gbe->vt_xy;
286 if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
287 udelay(10);
288 else
289 break;
290 }
291 if (i == 10000)
292 printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
293
294 /* turn off dot clock */
295 val = gbe->dotclock;
296 SET_GBE_FIELD(DOTCLK, RUN, val, 0);
297 gbe->dotclock = val;
298 udelay(10000);
299 for (i = 0; i < 10000; i++) {
300 val = gbe->dotclock;
301 if (GET_GBE_FIELD(DOTCLK, RUN, val))
302 udelay(10);
303 else
304 break;
305 }
306 if (i == 10000)
307 printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
308
309 /* reset the frame DMA FIFO */
310 val = gbe->frm_size_tile;
311 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
312 gbe->frm_size_tile = val;
313 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
314 gbe->frm_size_tile = val;
315}
316
317static void gbe_turn_on(void)
318{
319 unsigned int val, i;
320
321 /*
322 * Check if pixel counter is off, for unknown reason this
323 * code hangs Visual Workstations
324 */
325 if (gbe_revision < 2) {
326 val = gbe->vt_xy;
327 if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
328 return;
329 }
330
331 /* turn on dot clock */
332 val = gbe->dotclock;
333 SET_GBE_FIELD(DOTCLK, RUN, val, 1);
334 gbe->dotclock = val;
335 udelay(10000);
336 for (i = 0; i < 10000; i++) {
337 val = gbe->dotclock;
338 if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
339 udelay(10);
340 else
341 break;
342 }
343 if (i == 10000)
344 printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
345
346 /* turn on pixel counter */
347 val = 0;
348 SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
349 gbe->vt_xy = val;
350 udelay(10000);
351 for (i = 0; i < 10000; i++) {
352 val = gbe->vt_xy;
353 if (GET_GBE_FIELD(VT_XY, FREEZE, val))
354 udelay(10);
355 else
356 break;
357 }
358 if (i == 10000)
359 printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
360
361 /* turn on DMA */
362 val = gbe->frm_control;
363 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
364 gbe->frm_control = val;
365 udelay(1000);
366 for (i = 0; i < 10000; i++) {
367 val = gbe->frm_inhwctrl;
368 if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
369 udelay(10);
370 else
371 break;
372 }
373 if (i == 10000)
374 printk(KERN_ERR "gbefb: turn on DMA timed out\n");
375}
376
377/*
378 * Blank the display.
379 */
380static int gbefb_blank(int blank, struct fb_info *info)
381{
382 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
383 switch (blank) {
384 case FB_BLANK_UNBLANK: /* unblank */
385 gbe_turn_on();
386 break;
387
388 case FB_BLANK_NORMAL: /* blank */
389 gbe_turn_off();
390 break;
391
392 default:
393 /* Nothing */
394 break;
395 }
396 return 0;
397}
398
399/*
400 * Setup flatpanel related registers.
401 */
402static void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
403{
404 int fp_wid, fp_hgt, fp_vbs, fp_vbe;
405 u32 outputVal = 0;
406
407 SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
408 (timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
409 SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
410 (timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
411 gbe->vt_flags = outputVal;
412
413 /* Turn on the flat panel */
414 fp_wid = 1600;
415 fp_hgt = 1024;
416 fp_vbs = 0;
417 fp_vbe = 1600;
418 timing->pll_m = 4;
419 timing->pll_n = 1;
420 timing->pll_p = 0;
421
422 outputVal = 0;
423 SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
424 SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
425 gbe->fp_de = outputVal;
426 outputVal = 0;
427 SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
428 gbe->fp_hdrv = outputVal;
429 outputVal = 0;
430 SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
431 SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
432 gbe->fp_vdrv = outputVal;
433}
434
435struct gbe_pll_info {
436 int clock_rate;
437 int fvco_min;
438 int fvco_max;
439};
440
441static struct gbe_pll_info gbe_pll_table[2] = {
442 { 20, 80, 220 },
443 { 27, 80, 220 },
444};
445
446static int compute_gbe_timing(struct fb_var_screeninfo *var,
447 struct gbe_timing_info *timing)
448{
449 int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
450 int pixclock;
451 struct gbe_pll_info *gbe_pll;
452
453 if (gbe_revision < 2)
454 gbe_pll = &gbe_pll_table[0];
455 else
456 gbe_pll = &gbe_pll_table[1];
457
458 /* Determine valid resolution and timing
459 * GBE crystal runs at 20Mhz or 27Mhz
460 * pll_m, pll_n, pll_p define the following frequencies
461 * fvco = pll_m * 20Mhz / pll_n
462 * fout = fvco / (2**pll_p) */
463 best_error = 1000000000;
464 best_n = best_m = best_p = 0;
465 for (pll_p = 0; pll_p < 4; pll_p++)
466 for (pll_m = 1; pll_m < 256; pll_m++)
467 for (pll_n = 1; pll_n < 64; pll_n++) {
468 pixclock = (1000000 / gbe_pll->clock_rate) *
469 (pll_n << pll_p) / pll_m;
470
471 error = var->pixclock - pixclock;
472
473 if (error < 0)
474 error = -error;
475
476 if (error < best_error &&
477 pll_m / pll_n >
478 gbe_pll->fvco_min / gbe_pll->clock_rate &&
479 pll_m / pll_n <
480 gbe_pll->fvco_max / gbe_pll->clock_rate) {
481 best_error = error;
482 best_m = pll_m;
483 best_n = pll_n;
484 best_p = pll_p;
485 }
486 }
487
488 if (!best_n || !best_m)
489 return -EINVAL; /* Resolution to high */
490
491 pixclock = (1000000 / gbe_pll->clock_rate) *
492 (best_n << best_p) / best_m;
493
494 /* set video timing information */
495 if (timing) {
496 timing->width = var->xres;
497 timing->height = var->yres;
498 timing->pll_m = best_m;
499 timing->pll_n = best_n;
500 timing->pll_p = best_p;
501 timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
502 (timing->pll_n << timing->pll_p);
503 timing->htotal = var->left_margin + var->xres +
504 var->right_margin + var->hsync_len;
505 timing->vtotal = var->upper_margin + var->yres +
506 var->lower_margin + var->vsync_len;
507 timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
508 1000 / timing->vtotal;
509 timing->hblank_start = var->xres;
510 timing->vblank_start = var->yres;
511 timing->hblank_end = timing->htotal;
512 timing->hsync_start = var->xres + var->right_margin + 1;
513 timing->hsync_end = timing->hsync_start + var->hsync_len;
514 timing->vblank_end = timing->vtotal;
515 timing->vsync_start = var->yres + var->lower_margin + 1;
516 timing->vsync_end = timing->vsync_start + var->vsync_len;
517 }
518
519 return pixclock;
520}
521
522static void gbe_set_timing_info(struct gbe_timing_info *timing)
523{
524 int temp;
525 unsigned int val;
526
527 /* setup dot clock PLL */
528 val = 0;
529 SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
530 SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
531 SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
532 SET_GBE_FIELD(DOTCLK, RUN, val, 0); /* do not start yet */
533 gbe->dotclock = val;
534 udelay(10000);
535
536 /* setup pixel counter */
537 val = 0;
538 SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
539 SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
540 gbe->vt_xymax = val;
541
542 /* setup video timing signals */
543 val = 0;
544 SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
545 SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
546 gbe->vt_vsync = val;
547 val = 0;
548 SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
549 SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
550 gbe->vt_hsync = val;
551 val = 0;
552 SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
553 SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
554 gbe->vt_vblank = val;
555 val = 0;
556 SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
557 timing->hblank_start - 5);
558 SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
559 timing->hblank_end - 3);
560 gbe->vt_hblank = val;
561
562 /* setup internal timing signals */
563 val = 0;
564 SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
565 SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
566 gbe->vt_vcmap = val;
567 val = 0;
568 SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
569 SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
570 gbe->vt_hcmap = val;
571
572 val = 0;
573 temp = timing->vblank_start - timing->vblank_end - 1;
574 if (temp > 0)
575 temp = -temp;
576
577 if (flat_panel_enabled)
578 gbefb_setup_flatpanel(timing);
579
580 SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
581 if (timing->hblank_end >= 20)
582 SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
583 timing->hblank_end - 20);
584 else
585 SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
586 timing->htotal - (20 - timing->hblank_end));
587 gbe->did_start_xy = val;
588
589 val = 0;
590 SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
591 if (timing->hblank_end >= GBE_CRS_MAGIC)
592 SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
593 timing->hblank_end - GBE_CRS_MAGIC);
594 else
595 SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
596 timing->htotal - (GBE_CRS_MAGIC -
597 timing->hblank_end));
598 gbe->crs_start_xy = val;
599
600 val = 0;
601 SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
602 SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
603 gbe->vc_start_xy = val;
604
605 val = 0;
606 temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
607 if (temp < 0)
608 temp += timing->htotal; /* allow blank to wrap around */
609
610 SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
611 SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
612 ((temp + timing->width -
613 GBE_PIXEN_MAGIC_OFF) % timing->htotal));
614 gbe->vt_hpixen = val;
615
616 val = 0;
617 SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
618 SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
619 gbe->vt_vpixen = val;
620
621 /* turn off sync on green */
622 val = 0;
623 SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
624 gbe->vt_flags = val;
625}
626
627/*
628 * Set the hardware according to 'par'.
629 */
630
631static int gbefb_set_par(struct fb_info *info)
632{
633 int i;
634 unsigned int val;
635 int wholeTilesX, partTilesX, maxPixelsPerTileX;
636 int height_pix;
637 int xpmax, ypmax; /* Monitor resolution */
638 int bytesPerPixel; /* Bytes per pixel */
639 struct gbefb_par *par = (struct gbefb_par *) info->par;
640
641 compute_gbe_timing(&info->var, &par->timing);
642
643 bytesPerPixel = info->var.bits_per_pixel / 8;
644 info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
645 xpmax = par->timing.width;
646 ypmax = par->timing.height;
647
648 /* turn off GBE */
649 gbe_turn_off();
650
651 /* set timing info */
652 gbe_set_timing_info(&par->timing);
653
654 /* initialize DIDs */
655 val = 0;
656 switch (bytesPerPixel) {
657 case 1:
658 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800659 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 break;
661 case 2:
662 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800663 info->fix.visual = FB_VISUAL_TRUECOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 break;
665 case 4:
666 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800667 info->fix.visual = FB_VISUAL_TRUECOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 break;
669 }
670 SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
671
672 for (i = 0; i < 32; i++)
673 gbe->mode_regs[i] = val;
674
675 /* Initialize interrupts */
676 gbe->vt_intr01 = 0xffffffff;
677 gbe->vt_intr23 = 0xffffffff;
678
679 /* HACK:
680 The GBE hardware uses a tiled memory to screen mapping. Tiles are
681 blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
682 16bit and 32 bit modes (64 kB). They cover the screen with partial
683 tiles on the right and/or bottom of the screen if needed.
684 For exemple in 640x480 8 bit mode the mapping is:
685
686 <-------- 640 ----->
687 <---- 512 ----><128|384 offscreen>
688 ^ ^
689 | 128 [tile 0] [tile 1]
690 | v
691 ^
692 4 128 [tile 2] [tile 3]
693 8 v
694 0 ^
695 128 [tile 4] [tile 5]
696 | v
697 | ^
698 v 96 [tile 6] [tile 7]
699 32 offscreen
700
701 Tiles have the advantage that they can be allocated individually in
702 memory. However, this mapping is not linear at all, which is not
703 really convienient. In order to support linear addressing, the GBE
704 DMA hardware is fooled into thinking the screen is only one tile
705 large and but has a greater height, so that the DMA transfer covers
706 the same region.
707 Tiles are still allocated as independent chunks of 64KB of
708 continuous physical memory and remapped so that the kernel sees the
709 framebuffer as a continuous virtual memory. The GBE tile table is
710 set up so that each tile references one of these 64k blocks:
711
712 GBE -> tile list framebuffer TLB <------------ CPU
713 [ tile 0 ] -> [ 64KB ] <- [ 16x 4KB page entries ] ^
714 ... ... ... linear virtual FB
715 [ tile n ] -> [ 64KB ] <- [ 16x 4KB page entries ] v
716
717
718 The GBE hardware is then told that the buffer is 512*tweaked_height,
719 with tweaked_height = real_width*real_height/pixels_per_tile.
720 Thus the GBE hardware will scan the first tile, filing the first 64k
721 covered region of the screen, and then will proceed to the next
722 tile, until the whole screen is covered.
723
724 Here is what would happen at 640x480 8bit:
725
726 normal tiling linear
727 ^ 11111111111111112222 11111111111111111111 ^
728 128 11111111111111112222 11111111111111111111 102 lines
729 11111111111111112222 11111111111111111111 v
730 V 11111111111111112222 11111111222222222222
731 33333333333333334444 22222222222222222222
732 33333333333333334444 22222222222222222222
733 < 512 > < 256 > 102*640+256 = 64k
734
735 NOTE: The only mode for which this is not working is 800x600 8bit,
736 as 800*600/512 = 937.5 which is not integer and thus causes
737 flickering.
738 I guess this is not so important as one can use 640x480 8bit or
739 800x600 16bit anyway.
740 */
741
742 /* Tell gbe about the tiles table location */
743 /* tile_ptr -> [ tile 1 ] -> FB mem */
744 /* [ tile 2 ] -> FB mem */
745 /* ... */
746 val = 0;
747 SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
748 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
749 SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
750 gbe->frm_control = val;
751
752 maxPixelsPerTileX = 512 / bytesPerPixel;
753 wholeTilesX = 1;
754 partTilesX = 0;
755
756 /* Initialize the framebuffer */
757 val = 0;
758 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
759 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
760
761 switch (bytesPerPixel) {
762 case 1:
763 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
764 GBE_FRM_DEPTH_8);
765 break;
766 case 2:
767 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
768 GBE_FRM_DEPTH_16);
769 break;
770 case 4:
771 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
772 GBE_FRM_DEPTH_32);
773 break;
774 }
775 gbe->frm_size_tile = val;
776
777 /* compute tweaked height */
778 height_pix = xpmax * ypmax / maxPixelsPerTileX;
779
780 val = 0;
781 SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
782 gbe->frm_size_pixel = val;
783
784 /* turn off DID and overlay DMA */
785 gbe->did_control = 0;
786 gbe->ovr_width_tile = 0;
787
788 /* Turn off mouse cursor */
789 gbe->crs_ctl = 0;
790
791 /* Turn on GBE */
792 gbe_turn_on();
793
794 /* Initialize the gamma map */
795 udelay(10);
796 for (i = 0; i < 256; i++)
797 gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
798
799 /* Initialize the color map */
800 for (i = 0; i < 256; i++) {
801 int j;
802
803 for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
804 udelay(10);
805 if (j == 1000)
806 printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
807
808 gbe->cmap[i] = (i << 8) | (i << 16) | (i << 24);
809 }
810
811 return 0;
812}
813
814static void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
815 struct fb_var_screeninfo *var)
816{
817 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
818 strcpy(fix->id, "SGI GBE");
819 fix->smem_start = (unsigned long) gbe_mem;
820 fix->smem_len = gbe_mem_size;
821 fix->type = FB_TYPE_PACKED_PIXELS;
822 fix->type_aux = 0;
823 fix->accel = FB_ACCEL_NONE;
824 switch (var->bits_per_pixel) {
825 case 8:
826 fix->visual = FB_VISUAL_PSEUDOCOLOR;
827 break;
828 default:
829 fix->visual = FB_VISUAL_TRUECOLOR;
830 break;
831 }
832 fix->ywrapstep = 0;
833 fix->xpanstep = 0;
834 fix->ypanstep = 0;
835 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
836 fix->mmio_start = GBE_BASE;
837 fix->mmio_len = sizeof(struct sgi_gbe);
838}
839
840/*
841 * Set a single color register. The values supplied are already
842 * rounded down to the hardware's capabilities (according to the
843 * entries in the var structure). Return != 0 for invalid regno.
844 */
845
846static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
847 unsigned blue, unsigned transp,
848 struct fb_info *info)
849{
850 int i;
851
852 if (regno > 255)
853 return 1;
854 red >>= 8;
855 green >>= 8;
856 blue >>= 8;
857
858 switch (info->var.bits_per_pixel) {
859 case 8:
860 /* wait for the color map FIFO to have a free entry */
861 for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
862 udelay(10);
863 if (i == 1000) {
864 printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
865 return 1;
866 }
867 gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
868 break;
869 case 15:
870 case 16:
871 red >>= 3;
872 green >>= 3;
873 blue >>= 3;
874 pseudo_palette[regno] =
875 (red << info->var.red.offset) |
876 (green << info->var.green.offset) |
877 (blue << info->var.blue.offset);
878 break;
879 case 32:
880 pseudo_palette[regno] =
881 (red << info->var.red.offset) |
882 (green << info->var.green.offset) |
883 (blue << info->var.blue.offset);
884 break;
885 }
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");