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