blob: 6d9ef39810c8eed2c8efe34b3087ab95971595a1 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070048/* macro for fastest write-though access to the framebuffer */
49#ifdef CONFIG_MIPS
50#ifdef CONFIG_CPU_R10000
51#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)
52#else
53#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)
54#endif
55#endif
56#ifdef CONFIG_X86
Juergen Gross2d85ebf2014-11-03 14:01:49 +010057#define pgprot_fb(_prot) (((_prot) & ~_PAGE_CACHE_MASK) | \
58 cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS))
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#endif
60
61/*
62 * RAM we reserve for the frame buffer. This defines the maximum screen
63 * size
64 */
65#if CONFIG_FB_GBE_MEM > 8
66#error GBE Framebuffer cannot use more than 8MB of memory
67#endif
68
69#define TILE_SHIFT 16
70#define TILE_SIZE (1 << TILE_SHIFT)
71#define TILE_MASK (TILE_SIZE - 1)
72
73static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;
74static void *gbe_mem;
75static dma_addr_t gbe_dma_addr;
Dmitri Vorobievb6d57ae2009-03-30 22:53:26 +030076static unsigned long gbe_mem_phys;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78static struct {
79 uint16_t *cpu;
80 dma_addr_t dma;
81} gbe_tiles;
82
83static int gbe_revision;
84
85static int ypan, ywrap;
86
Antonino A. Daplas9058be42007-07-17 04:05:37 -070087static uint32_t pseudo_palette[16];
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -070088static uint32_t gbe_cmap[256];
89static int gbe_turned_on; /* 0 turned off, 1 turned on */
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080091static char *mode_option = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* default CRT mode */
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -080094static struct fb_var_screeninfo default_var_CRT = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 /* 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 */
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800125static struct fb_var_screeninfo default_var_LCD = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 /* 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) */
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800157static struct fb_videomode default_mode_CRT = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 .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 */
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800172static struct fb_videomode default_mode_LCD = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 /* 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
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800186static struct fb_videomode *default_mode = &default_mode_CRT;
187static struct fb_var_screeninfo *default_var = &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
Dmitri Vorobievb6d57ae2009-03-30 22:53:26 +0300206static void gbe_turn_off(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 int i;
209 unsigned int val, x, y, vpixen_off;
210
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700211 gbe_turned_on = 0;
212
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 /* check if pixel counter is on */
214 val = gbe->vt_xy;
215 if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1)
216 return;
217
218 /* turn off DMA */
219 val = gbe->ovr_control;
220 SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0);
221 gbe->ovr_control = val;
222 udelay(1000);
223 val = gbe->frm_control;
224 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0);
225 gbe->frm_control = val;
226 udelay(1000);
227 val = gbe->did_control;
228 SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0);
229 gbe->did_control = val;
230 udelay(1000);
231
232 /* We have to wait through two vertical retrace periods before
233 * the pixel DMA is turned off for sure. */
234 for (i = 0; i < 10000; i++) {
235 val = gbe->frm_inhwctrl;
236 if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) {
237 udelay(10);
238 } else {
239 val = gbe->ovr_inhwctrl;
240 if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) {
241 udelay(10);
242 } else {
243 val = gbe->did_inhwctrl;
244 if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) {
245 udelay(10);
246 } else
247 break;
248 }
249 }
250 }
251 if (i == 10000)
252 printk(KERN_ERR "gbefb: turn off DMA timed out\n");
253
254 /* wait for vpixen_off */
255 val = gbe->vt_vpixen;
256 vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val);
257
258 for (i = 0; i < 100000; i++) {
259 val = gbe->vt_xy;
260 x = GET_GBE_FIELD(VT_XY, X, val);
261 y = GET_GBE_FIELD(VT_XY, Y, val);
262 if (y < vpixen_off)
263 break;
264 udelay(1);
265 }
266 if (i == 100000)
267 printk(KERN_ERR
268 "gbefb: wait for vpixen_off timed out\n");
269 for (i = 0; i < 10000; i++) {
270 val = gbe->vt_xy;
271 x = GET_GBE_FIELD(VT_XY, X, val);
272 y = GET_GBE_FIELD(VT_XY, Y, val);
273 if (y > vpixen_off)
274 break;
275 udelay(1);
276 }
277 if (i == 10000)
278 printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n");
279
280 /* turn off pixel counter */
281 val = 0;
282 SET_GBE_FIELD(VT_XY, FREEZE, val, 1);
283 gbe->vt_xy = val;
284 udelay(10000);
285 for (i = 0; i < 10000; i++) {
286 val = gbe->vt_xy;
287 if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1)
288 udelay(10);
289 else
290 break;
291 }
292 if (i == 10000)
293 printk(KERN_ERR "gbefb: turn off pixel clock timed out\n");
294
295 /* turn off dot clock */
296 val = gbe->dotclock;
297 SET_GBE_FIELD(DOTCLK, RUN, val, 0);
298 gbe->dotclock = val;
299 udelay(10000);
300 for (i = 0; i < 10000; i++) {
301 val = gbe->dotclock;
302 if (GET_GBE_FIELD(DOTCLK, RUN, val))
303 udelay(10);
304 else
305 break;
306 }
307 if (i == 10000)
308 printk(KERN_ERR "gbefb: turn off dotclock timed out\n");
309
310 /* reset the frame DMA FIFO */
311 val = gbe->frm_size_tile;
312 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1);
313 gbe->frm_size_tile = val;
314 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0);
315 gbe->frm_size_tile = val;
316}
317
318static void gbe_turn_on(void)
319{
320 unsigned int val, i;
321
322 /*
323 * Check if pixel counter is off, for unknown reason this
324 * code hangs Visual Workstations
325 */
326 if (gbe_revision < 2) {
327 val = gbe->vt_xy;
328 if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0)
329 return;
330 }
331
332 /* turn on dot clock */
333 val = gbe->dotclock;
334 SET_GBE_FIELD(DOTCLK, RUN, val, 1);
335 gbe->dotclock = val;
336 udelay(10000);
337 for (i = 0; i < 10000; i++) {
338 val = gbe->dotclock;
339 if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1)
340 udelay(10);
341 else
342 break;
343 }
344 if (i == 10000)
345 printk(KERN_ERR "gbefb: turn on dotclock timed out\n");
346
347 /* turn on pixel counter */
348 val = 0;
349 SET_GBE_FIELD(VT_XY, FREEZE, val, 0);
350 gbe->vt_xy = val;
351 udelay(10000);
352 for (i = 0; i < 10000; i++) {
353 val = gbe->vt_xy;
354 if (GET_GBE_FIELD(VT_XY, FREEZE, val))
355 udelay(10);
356 else
357 break;
358 }
359 if (i == 10000)
360 printk(KERN_ERR "gbefb: turn on pixel clock timed out\n");
361
362 /* turn on DMA */
363 val = gbe->frm_control;
364 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1);
365 gbe->frm_control = val;
366 udelay(1000);
367 for (i = 0; i < 10000; i++) {
368 val = gbe->frm_inhwctrl;
369 if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1)
370 udelay(10);
371 else
372 break;
373 }
374 if (i == 10000)
375 printk(KERN_ERR "gbefb: turn on DMA timed out\n");
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700376
377 gbe_turned_on = 1;
378}
379
380static void gbe_loadcmap(void)
381{
382 int i, j;
383
384 for (i = 0; i < 256; i++) {
385 for (j = 0; j < 1000 && gbe->cm_fifo >= 63; j++)
386 udelay(10);
387 if (j == 1000)
388 printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
389
390 gbe->cmap[i] = gbe_cmap[i];
391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392}
393
394/*
395 * Blank the display.
396 */
397static int gbefb_blank(int blank, struct fb_info *info)
398{
399 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
400 switch (blank) {
401 case FB_BLANK_UNBLANK: /* unblank */
402 gbe_turn_on();
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700403 gbe_loadcmap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 break;
405
406 case FB_BLANK_NORMAL: /* blank */
407 gbe_turn_off();
408 break;
409
410 default:
411 /* Nothing */
412 break;
413 }
414 return 0;
415}
416
417/*
418 * Setup flatpanel related registers.
419 */
420static void gbefb_setup_flatpanel(struct gbe_timing_info *timing)
421{
422 int fp_wid, fp_hgt, fp_vbs, fp_vbe;
423 u32 outputVal = 0;
424
425 SET_GBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal,
426 (timing->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
427 SET_GBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal,
428 (timing->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
429 gbe->vt_flags = outputVal;
430
431 /* Turn on the flat panel */
432 fp_wid = 1600;
433 fp_hgt = 1024;
434 fp_vbs = 0;
435 fp_vbe = 1600;
436 timing->pll_m = 4;
437 timing->pll_n = 1;
438 timing->pll_p = 0;
439
440 outputVal = 0;
441 SET_GBE_FIELD(FP_DE, ON, outputVal, fp_vbs);
442 SET_GBE_FIELD(FP_DE, OFF, outputVal, fp_vbe);
443 gbe->fp_de = outputVal;
444 outputVal = 0;
445 SET_GBE_FIELD(FP_HDRV, OFF, outputVal, fp_wid);
446 gbe->fp_hdrv = outputVal;
447 outputVal = 0;
448 SET_GBE_FIELD(FP_VDRV, ON, outputVal, 1);
449 SET_GBE_FIELD(FP_VDRV, OFF, outputVal, fp_hgt + 1);
450 gbe->fp_vdrv = outputVal;
451}
452
453struct gbe_pll_info {
454 int clock_rate;
455 int fvco_min;
456 int fvco_max;
457};
458
459static struct gbe_pll_info gbe_pll_table[2] = {
460 { 20, 80, 220 },
461 { 27, 80, 220 },
462};
463
464static int compute_gbe_timing(struct fb_var_screeninfo *var,
465 struct gbe_timing_info *timing)
466{
467 int pll_m, pll_n, pll_p, error, best_m, best_n, best_p, best_error;
468 int pixclock;
469 struct gbe_pll_info *gbe_pll;
470
471 if (gbe_revision < 2)
472 gbe_pll = &gbe_pll_table[0];
473 else
474 gbe_pll = &gbe_pll_table[1];
475
476 /* Determine valid resolution and timing
477 * GBE crystal runs at 20Mhz or 27Mhz
478 * pll_m, pll_n, pll_p define the following frequencies
479 * fvco = pll_m * 20Mhz / pll_n
480 * fout = fvco / (2**pll_p) */
481 best_error = 1000000000;
482 best_n = best_m = best_p = 0;
483 for (pll_p = 0; pll_p < 4; pll_p++)
484 for (pll_m = 1; pll_m < 256; pll_m++)
485 for (pll_n = 1; pll_n < 64; pll_n++) {
486 pixclock = (1000000 / gbe_pll->clock_rate) *
487 (pll_n << pll_p) / pll_m;
488
489 error = var->pixclock - pixclock;
490
491 if (error < 0)
492 error = -error;
493
494 if (error < best_error &&
495 pll_m / pll_n >
496 gbe_pll->fvco_min / gbe_pll->clock_rate &&
497 pll_m / pll_n <
498 gbe_pll->fvco_max / gbe_pll->clock_rate) {
499 best_error = error;
500 best_m = pll_m;
501 best_n = pll_n;
502 best_p = pll_p;
503 }
504 }
505
506 if (!best_n || !best_m)
507 return -EINVAL; /* Resolution to high */
508
509 pixclock = (1000000 / gbe_pll->clock_rate) *
510 (best_n << best_p) / best_m;
511
512 /* set video timing information */
513 if (timing) {
514 timing->width = var->xres;
515 timing->height = var->yres;
516 timing->pll_m = best_m;
517 timing->pll_n = best_n;
518 timing->pll_p = best_p;
519 timing->cfreq = gbe_pll->clock_rate * 1000 * timing->pll_m /
520 (timing->pll_n << timing->pll_p);
521 timing->htotal = var->left_margin + var->xres +
522 var->right_margin + var->hsync_len;
523 timing->vtotal = var->upper_margin + var->yres +
524 var->lower_margin + var->vsync_len;
525 timing->fields_sec = 1000 * timing->cfreq / timing->htotal *
526 1000 / timing->vtotal;
527 timing->hblank_start = var->xres;
528 timing->vblank_start = var->yres;
529 timing->hblank_end = timing->htotal;
530 timing->hsync_start = var->xres + var->right_margin + 1;
531 timing->hsync_end = timing->hsync_start + var->hsync_len;
532 timing->vblank_end = timing->vtotal;
533 timing->vsync_start = var->yres + var->lower_margin + 1;
534 timing->vsync_end = timing->vsync_start + var->vsync_len;
535 }
536
537 return pixclock;
538}
539
540static void gbe_set_timing_info(struct gbe_timing_info *timing)
541{
542 int temp;
543 unsigned int val;
544
545 /* setup dot clock PLL */
546 val = 0;
547 SET_GBE_FIELD(DOTCLK, M, val, timing->pll_m - 1);
548 SET_GBE_FIELD(DOTCLK, N, val, timing->pll_n - 1);
549 SET_GBE_FIELD(DOTCLK, P, val, timing->pll_p);
550 SET_GBE_FIELD(DOTCLK, RUN, val, 0); /* do not start yet */
551 gbe->dotclock = val;
552 udelay(10000);
553
554 /* setup pixel counter */
555 val = 0;
556 SET_GBE_FIELD(VT_XYMAX, MAXX, val, timing->htotal);
557 SET_GBE_FIELD(VT_XYMAX, MAXY, val, timing->vtotal);
558 gbe->vt_xymax = val;
559
560 /* setup video timing signals */
561 val = 0;
562 SET_GBE_FIELD(VT_VSYNC, VSYNC_ON, val, timing->vsync_start);
563 SET_GBE_FIELD(VT_VSYNC, VSYNC_OFF, val, timing->vsync_end);
564 gbe->vt_vsync = val;
565 val = 0;
566 SET_GBE_FIELD(VT_HSYNC, HSYNC_ON, val, timing->hsync_start);
567 SET_GBE_FIELD(VT_HSYNC, HSYNC_OFF, val, timing->hsync_end);
568 gbe->vt_hsync = val;
569 val = 0;
570 SET_GBE_FIELD(VT_VBLANK, VBLANK_ON, val, timing->vblank_start);
571 SET_GBE_FIELD(VT_VBLANK, VBLANK_OFF, val, timing->vblank_end);
572 gbe->vt_vblank = val;
573 val = 0;
574 SET_GBE_FIELD(VT_HBLANK, HBLANK_ON, val,
575 timing->hblank_start - 5);
576 SET_GBE_FIELD(VT_HBLANK, HBLANK_OFF, val,
577 timing->hblank_end - 3);
578 gbe->vt_hblank = val;
579
580 /* setup internal timing signals */
581 val = 0;
582 SET_GBE_FIELD(VT_VCMAP, VCMAP_ON, val, timing->vblank_start);
583 SET_GBE_FIELD(VT_VCMAP, VCMAP_OFF, val, timing->vblank_end);
584 gbe->vt_vcmap = val;
585 val = 0;
586 SET_GBE_FIELD(VT_HCMAP, HCMAP_ON, val, timing->hblank_start);
587 SET_GBE_FIELD(VT_HCMAP, HCMAP_OFF, val, timing->hblank_end);
588 gbe->vt_hcmap = val;
589
590 val = 0;
591 temp = timing->vblank_start - timing->vblank_end - 1;
592 if (temp > 0)
593 temp = -temp;
594
595 if (flat_panel_enabled)
596 gbefb_setup_flatpanel(timing);
597
598 SET_GBE_FIELD(DID_START_XY, DID_STARTY, val, (u32) temp);
599 if (timing->hblank_end >= 20)
600 SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
601 timing->hblank_end - 20);
602 else
603 SET_GBE_FIELD(DID_START_XY, DID_STARTX, val,
604 timing->htotal - (20 - timing->hblank_end));
605 gbe->did_start_xy = val;
606
607 val = 0;
608 SET_GBE_FIELD(CRS_START_XY, CRS_STARTY, val, (u32) (temp + 1));
609 if (timing->hblank_end >= GBE_CRS_MAGIC)
610 SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
611 timing->hblank_end - GBE_CRS_MAGIC);
612 else
613 SET_GBE_FIELD(CRS_START_XY, CRS_STARTX, val,
614 timing->htotal - (GBE_CRS_MAGIC -
615 timing->hblank_end));
616 gbe->crs_start_xy = val;
617
618 val = 0;
619 SET_GBE_FIELD(VC_START_XY, VC_STARTY, val, (u32) temp);
620 SET_GBE_FIELD(VC_START_XY, VC_STARTX, val, timing->hblank_end - 4);
621 gbe->vc_start_xy = val;
622
623 val = 0;
624 temp = timing->hblank_end - GBE_PIXEN_MAGIC_ON;
625 if (temp < 0)
626 temp += timing->htotal; /* allow blank to wrap around */
627
628 SET_GBE_FIELD(VT_HPIXEN, HPIXEN_ON, val, temp);
629 SET_GBE_FIELD(VT_HPIXEN, HPIXEN_OFF, val,
630 ((temp + timing->width -
631 GBE_PIXEN_MAGIC_OFF) % timing->htotal));
632 gbe->vt_hpixen = val;
633
634 val = 0;
635 SET_GBE_FIELD(VT_VPIXEN, VPIXEN_ON, val, timing->vblank_end);
636 SET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val, timing->vblank_start);
637 gbe->vt_vpixen = val;
638
639 /* turn off sync on green */
640 val = 0;
641 SET_GBE_FIELD(VT_FLAGS, SYNC_LOW, val, 1);
642 gbe->vt_flags = val;
643}
644
645/*
646 * Set the hardware according to 'par'.
647 */
648
649static int gbefb_set_par(struct fb_info *info)
650{
651 int i;
652 unsigned int val;
653 int wholeTilesX, partTilesX, maxPixelsPerTileX;
654 int height_pix;
655 int xpmax, ypmax; /* Monitor resolution */
656 int bytesPerPixel; /* Bytes per pixel */
657 struct gbefb_par *par = (struct gbefb_par *) info->par;
658
659 compute_gbe_timing(&info->var, &par->timing);
660
661 bytesPerPixel = info->var.bits_per_pixel / 8;
662 info->fix.line_length = info->var.xres_virtual * bytesPerPixel;
663 xpmax = par->timing.width;
664 ypmax = par->timing.height;
665
666 /* turn off GBE */
667 gbe_turn_off();
668
669 /* set timing info */
670 gbe_set_timing_info(&par->timing);
671
672 /* initialize DIDs */
673 val = 0;
674 switch (bytesPerPixel) {
675 case 1:
676 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800677 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 break;
679 case 2:
680 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800681 info->fix.visual = FB_VISUAL_TRUECOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 break;
683 case 4:
684 SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8);
Kaj-Michael Lang68b06de2006-02-24 13:04:15 -0800685 info->fix.visual = FB_VISUAL_TRUECOLOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 break;
687 }
688 SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH);
689
690 for (i = 0; i < 32; i++)
691 gbe->mode_regs[i] = val;
692
693 /* Initialize interrupts */
694 gbe->vt_intr01 = 0xffffffff;
695 gbe->vt_intr23 = 0xffffffff;
696
697 /* HACK:
698 The GBE hardware uses a tiled memory to screen mapping. Tiles are
699 blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
700 16bit and 32 bit modes (64 kB). They cover the screen with partial
701 tiles on the right and/or bottom of the screen if needed.
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200702 For example in 640x480 8 bit mode the mapping is:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
704 <-------- 640 ----->
705 <---- 512 ----><128|384 offscreen>
706 ^ ^
707 | 128 [tile 0] [tile 1]
708 | v
709 ^
710 4 128 [tile 2] [tile 3]
711 8 v
712 0 ^
713 128 [tile 4] [tile 5]
714 | v
715 | ^
716 v 96 [tile 6] [tile 7]
717 32 offscreen
718
719 Tiles have the advantage that they can be allocated individually in
720 memory. However, this mapping is not linear at all, which is not
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300721 really convenient. In order to support linear addressing, the GBE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 DMA hardware is fooled into thinking the screen is only one tile
723 large and but has a greater height, so that the DMA transfer covers
724 the same region.
725 Tiles are still allocated as independent chunks of 64KB of
726 continuous physical memory and remapped so that the kernel sees the
727 framebuffer as a continuous virtual memory. The GBE tile table is
728 set up so that each tile references one of these 64k blocks:
729
730 GBE -> tile list framebuffer TLB <------------ CPU
731 [ tile 0 ] -> [ 64KB ] <- [ 16x 4KB page entries ] ^
732 ... ... ... linear virtual FB
733 [ tile n ] -> [ 64KB ] <- [ 16x 4KB page entries ] v
734
735
736 The GBE hardware is then told that the buffer is 512*tweaked_height,
737 with tweaked_height = real_width*real_height/pixels_per_tile.
738 Thus the GBE hardware will scan the first tile, filing the first 64k
739 covered region of the screen, and then will proceed to the next
740 tile, until the whole screen is covered.
741
742 Here is what would happen at 640x480 8bit:
743
744 normal tiling linear
745 ^ 11111111111111112222 11111111111111111111 ^
746 128 11111111111111112222 11111111111111111111 102 lines
747 11111111111111112222 11111111111111111111 v
748 V 11111111111111112222 11111111222222222222
749 33333333333333334444 22222222222222222222
750 33333333333333334444 22222222222222222222
751 < 512 > < 256 > 102*640+256 = 64k
752
753 NOTE: The only mode for which this is not working is 800x600 8bit,
754 as 800*600/512 = 937.5 which is not integer and thus causes
755 flickering.
756 I guess this is not so important as one can use 640x480 8bit or
757 800x600 16bit anyway.
758 */
759
760 /* Tell gbe about the tiles table location */
761 /* tile_ptr -> [ tile 1 ] -> FB mem */
762 /* [ tile 2 ] -> FB mem */
763 /* ... */
764 val = 0;
765 SET_GBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, val, gbe_tiles.dma >> 9);
766 SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); /* do not start */
767 SET_GBE_FIELD(FRM_CONTROL, FRM_LINEAR, val, 0);
768 gbe->frm_control = val;
769
770 maxPixelsPerTileX = 512 / bytesPerPixel;
771 wholeTilesX = 1;
772 partTilesX = 0;
773
774 /* Initialize the framebuffer */
775 val = 0;
776 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, val, wholeTilesX);
777 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_RHS, val, partTilesX);
778
779 switch (bytesPerPixel) {
780 case 1:
781 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
782 GBE_FRM_DEPTH_8);
783 break;
784 case 2:
785 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
786 GBE_FRM_DEPTH_16);
787 break;
788 case 4:
789 SET_GBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, val,
790 GBE_FRM_DEPTH_32);
791 break;
792 }
793 gbe->frm_size_tile = val;
794
795 /* compute tweaked height */
796 height_pix = xpmax * ypmax / maxPixelsPerTileX;
797
798 val = 0;
799 SET_GBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, val, height_pix);
800 gbe->frm_size_pixel = val;
801
802 /* turn off DID and overlay DMA */
803 gbe->did_control = 0;
804 gbe->ovr_width_tile = 0;
805
806 /* Turn off mouse cursor */
807 gbe->crs_ctl = 0;
808
809 /* Turn on GBE */
810 gbe_turn_on();
811
812 /* Initialize the gamma map */
813 udelay(10);
814 for (i = 0; i < 256; i++)
815 gbe->gmap[i] = (i << 24) | (i << 16) | (i << 8);
816
817 /* Initialize the color map */
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700818 for (i = 0; i < 256; i++)
819 gbe_cmap[i] = (i << 8) | (i << 16) | (i << 24);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700821 gbe_loadcmap();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823 return 0;
824}
825
826static void gbefb_encode_fix(struct fb_fix_screeninfo *fix,
827 struct fb_var_screeninfo *var)
828{
829 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
830 strcpy(fix->id, "SGI GBE");
831 fix->smem_start = (unsigned long) gbe_mem;
832 fix->smem_len = gbe_mem_size;
833 fix->type = FB_TYPE_PACKED_PIXELS;
834 fix->type_aux = 0;
835 fix->accel = FB_ACCEL_NONE;
836 switch (var->bits_per_pixel) {
837 case 8:
838 fix->visual = FB_VISUAL_PSEUDOCOLOR;
839 break;
840 default:
841 fix->visual = FB_VISUAL_TRUECOLOR;
842 break;
843 }
844 fix->ywrapstep = 0;
845 fix->xpanstep = 0;
846 fix->ypanstep = 0;
847 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
848 fix->mmio_start = GBE_BASE;
849 fix->mmio_len = sizeof(struct sgi_gbe);
850}
851
852/*
853 * Set a single color register. The values supplied are already
854 * rounded down to the hardware's capabilities (according to the
855 * entries in the var structure). Return != 0 for invalid regno.
856 */
857
858static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
859 unsigned blue, unsigned transp,
860 struct fb_info *info)
861{
862 int i;
863
864 if (regno > 255)
865 return 1;
866 red >>= 8;
867 green >>= 8;
868 blue >>= 8;
869
Antonino A. Daplas9058be42007-07-17 04:05:37 -0700870 if (info->var.bits_per_pixel <= 8) {
Thomas Bogendoerfer8d0b1c52008-07-29 22:33:49 -0700871 gbe_cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
872 if (gbe_turned_on) {
873 /* wait for the color map FIFO to have a free entry */
874 for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
875 udelay(10);
876 if (i == 1000) {
877 printk(KERN_ERR "gbefb: cmap FIFO timeout\n");
878 return 1;
879 }
880 gbe->cmap[regno] = gbe_cmap[regno];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
Antonino A. Daplas9058be42007-07-17 04:05:37 -0700882 } else if (regno < 16) {
883 switch (info->var.bits_per_pixel) {
884 case 15:
885 case 16:
886 red >>= 3;
887 green >>= 3;
888 blue >>= 3;
889 pseudo_palette[regno] =
890 (red << info->var.red.offset) |
891 (green << info->var.green.offset) |
892 (blue << info->var.blue.offset);
893 break;
894 case 32:
895 pseudo_palette[regno] =
896 (red << info->var.red.offset) |
897 (green << info->var.green.offset) |
898 (blue << info->var.blue.offset);
899 break;
900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 }
902
903 return 0;
904}
905
906/*
907 * Check video mode validity, eventually modify var to best match.
908 */
909static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
910{
911 unsigned int line_length;
912 struct gbe_timing_info timing;
roel kluin64051412009-01-06 14:42:31 -0800913 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 /* Limit bpp to 8, 16, and 32 */
916 if (var->bits_per_pixel <= 8)
917 var->bits_per_pixel = 8;
918 else if (var->bits_per_pixel <= 16)
919 var->bits_per_pixel = 16;
920 else if (var->bits_per_pixel <= 32)
921 var->bits_per_pixel = 32;
922 else
923 return -EINVAL;
924
925 /* Check the mode can be mapped linearly with the tile table trick. */
926 /* This requires width x height x bytes/pixel be a multiple of 512 */
927 if ((var->xres * var->yres * var->bits_per_pixel) & 4095)
928 return -EINVAL;
929
930 var->grayscale = 0; /* No grayscale for now */
931
roel kluin64051412009-01-06 14:42:31 -0800932 ret = compute_gbe_timing(var, &timing);
933 var->pixclock = ret;
934 if (ret < 0)
935 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 /* Adjust virtual resolution, if necessary */
938 if (var->xres > var->xres_virtual || (!ywrap && !ypan))
939 var->xres_virtual = var->xres;
940 if (var->yres > var->yres_virtual || (!ywrap && !ypan))
941 var->yres_virtual = var->yres;
942
943 if (var->vmode & FB_VMODE_CONUPDATE) {
944 var->vmode |= FB_VMODE_YWRAP;
945 var->xoffset = info->var.xoffset;
946 var->yoffset = info->var.yoffset;
947 }
948
949 /* No grayscale for now */
950 var->grayscale = 0;
951
952 /* Memory limit */
953 line_length = var->xres_virtual * var->bits_per_pixel / 8;
954 if (line_length * var->yres_virtual > gbe_mem_size)
955 return -ENOMEM; /* Virtual resolution too high */
956
957 switch (var->bits_per_pixel) {
958 case 8:
959 var->red.offset = 0;
960 var->red.length = 8;
961 var->green.offset = 0;
962 var->green.length = 8;
963 var->blue.offset = 0;
964 var->blue.length = 8;
965 var->transp.offset = 0;
966 var->transp.length = 0;
967 break;
968 case 16: /* RGB 1555 */
969 var->red.offset = 10;
970 var->red.length = 5;
971 var->green.offset = 5;
972 var->green.length = 5;
973 var->blue.offset = 0;
974 var->blue.length = 5;
975 var->transp.offset = 0;
976 var->transp.length = 0;
977 break;
978 case 32: /* RGB 8888 */
979 var->red.offset = 24;
980 var->red.length = 8;
981 var->green.offset = 16;
982 var->green.length = 8;
983 var->blue.offset = 8;
984 var->blue.length = 8;
985 var->transp.offset = 0;
986 var->transp.length = 8;
987 break;
988 }
989 var->red.msb_right = 0;
990 var->green.msb_right = 0;
991 var->blue.msb_right = 0;
992 var->transp.msb_right = 0;
993
994 var->left_margin = timing.htotal - timing.hsync_end;
995 var->right_margin = timing.hsync_start - timing.width;
996 var->upper_margin = timing.vtotal - timing.vsync_end;
997 var->lower_margin = timing.vsync_start - timing.height;
998 var->hsync_len = timing.hsync_end - timing.hsync_start;
999 var->vsync_len = timing.vsync_end - timing.vsync_start;
1000
1001 return 0;
1002}
1003
Christoph Hellwig216d5262006-01-14 13:21:25 -08001004static int gbefb_mmap(struct fb_info *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 struct vm_area_struct *vma)
1006{
1007 unsigned long size = vma->vm_end - vma->vm_start;
1008 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
1009 unsigned long addr;
1010 unsigned long phys_addr, phys_size;
1011 u16 *tile;
1012
1013 /* check range */
1014 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1015 return -EINVAL;
Tomi Valkeinen04f8afb2013-04-18 08:39:47 +03001016 if (size > gbe_mem_size)
1017 return -EINVAL;
1018 if (offset > gbe_mem_size - size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return -EINVAL;
1020
1021 /* remap using the fastest write-through mode on architecture */
1022 /* try not polluting the cache when possible */
1023 pgprot_val(vma->vm_page_prot) =
1024 pgprot_fb(pgprot_val(vma->vm_page_prot));
1025
Konstantin Khlebnikov314e51b2012-10-08 16:29:02 -07001026 /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
1028 /* look for the starting tile */
1029 tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
1030 addr = vma->vm_start;
1031 offset &= TILE_MASK;
1032
1033 /* remap each tile separately */
1034 do {
1035 phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;
1036 if ((offset + size) < TILE_SIZE)
1037 phys_size = size;
1038 else
1039 phys_size = TILE_SIZE - offset;
1040
1041 if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,
1042 phys_size, vma->vm_page_prot))
1043 return -EAGAIN;
1044
1045 offset = 0;
1046 size -= phys_size;
1047 addr += phys_size;
1048 tile++;
1049 } while (size);
1050
1051 return 0;
1052}
1053
1054static struct fb_ops gbefb_ops = {
1055 .owner = THIS_MODULE,
1056 .fb_check_var = gbefb_check_var,
1057 .fb_set_par = gbefb_set_par,
1058 .fb_setcolreg = gbefb_setcolreg,
1059 .fb_mmap = gbefb_mmap,
1060 .fb_blank = gbefb_blank,
1061 .fb_fillrect = cfb_fillrect,
1062 .fb_copyarea = cfb_copyarea,
1063 .fb_imageblit = cfb_imageblit,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064};
1065
1066/*
1067 * sysfs
1068 */
1069
Yani Ioannou060b8842005-05-17 06:44:04 -04001070static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
Masanari Iida7e81b9d2014-04-29 21:21:55 +09001072 return snprintf(buf, PAGE_SIZE, "%u\n", gbe_mem_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073}
1074
1075static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
1076
Yani Ioannou060b8842005-05-17 06:44:04 -04001077static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078{
1079 return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision);
1080}
1081
1082static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
1083
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001084static void gbefb_remove_sysfs(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085{
1086 device_remove_file(dev, &dev_attr_size);
1087 device_remove_file(dev, &dev_attr_revision);
1088}
1089
1090static void gbefb_create_sysfs(struct device *dev)
1091{
1092 device_create_file(dev, &dev_attr_size);
1093 device_create_file(dev, &dev_attr_revision);
1094}
1095
1096/*
1097 * Initialization
1098 */
1099
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001100static int gbefb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101{
1102 char *this_opt;
1103
1104 if (!options || !*options)
1105 return 0;
1106
1107 while ((this_opt = strsep(&options, ",")) != NULL) {
1108 if (!strncmp(this_opt, "monitor:", 8)) {
1109 if (!strncmp(this_opt + 8, "crt", 3)) {
1110 flat_panel_enabled = 0;
1111 default_var = &default_var_CRT;
1112 default_mode = &default_mode_CRT;
1113 } else if (!strncmp(this_opt + 8, "1600sw", 6) ||
1114 !strncmp(this_opt + 8, "lcd", 3)) {
1115 flat_panel_enabled = 1;
1116 default_var = &default_var_LCD;
1117 default_mode = &default_mode_LCD;
1118 }
1119 } else if (!strncmp(this_opt, "mem:", 4)) {
1120 gbe_mem_size = memparse(this_opt + 4, &this_opt);
1121 if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)
1122 gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;
1123 if (gbe_mem_size < TILE_SIZE)
1124 gbe_mem_size = TILE_SIZE;
1125 } else
1126 mode_option = this_opt;
1127 }
1128 return 0;
1129}
1130
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001131static int gbefb_probe(struct platform_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132{
1133 int i, ret = 0;
1134 struct fb_info *info;
1135 struct gbefb_par *par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136#ifndef MODULE
1137 char *options = NULL;
1138#endif
1139
1140 info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev);
1141 if (!info)
1142 return -ENOMEM;
1143
1144#ifndef MODULE
Julia Lawallf3569102010-10-27 15:33:28 -07001145 if (fb_get_options("gbefb", &options)) {
1146 ret = -ENODEV;
1147 goto out_release_framebuffer;
1148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 gbefb_setup(options);
1150#endif
1151
Julia Lawall0fdd07f2009-08-09 11:42:32 +02001152 if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
1154 ret = -EBUSY;
1155 goto out_release_framebuffer;
1156 }
1157
Damien Cassouae1937f2012-07-31 18:39:19 +02001158 gbe = (struct sgi_gbe *) devm_ioremap(&p_dev->dev, GBE_BASE,
1159 sizeof(struct sgi_gbe));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (!gbe) {
1161 printk(KERN_ERR "gbefb: couldn't map mmio region\n");
1162 ret = -ENXIO;
1163 goto out_release_mem_region;
1164 }
1165 gbe_revision = gbe->ctrlstat & 15;
1166
1167 gbe_tiles.cpu =
1168 dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
1169 &gbe_tiles.dma, GFP_KERNEL);
1170 if (!gbe_tiles.cpu) {
1171 printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");
1172 ret = -ENOMEM;
Damien Cassouae1937f2012-07-31 18:39:19 +02001173 goto out_release_mem_region;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175
1176 if (gbe_mem_phys) {
1177 /* memory was allocated at boot time */
Damien Cassouae1937f2012-07-31 18:39:19 +02001178 gbe_mem = devm_ioremap_nocache(&p_dev->dev, gbe_mem_phys,
1179 gbe_mem_size);
Thiemo Seufer6d7bf012005-03-04 19:40:45 +00001180 if (!gbe_mem) {
1181 printk(KERN_ERR "gbefb: couldn't map framebuffer\n");
1182 ret = -ENOMEM;
1183 goto out_tiles_free;
1184 }
1185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 gbe_dma_addr = 0;
1187 } else {
1188 /* try to allocate memory with the classical allocator
1189 * this has high chance to fail on low memory machines */
1190 gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr,
1191 GFP_KERNEL);
Thiemo Seufer6d7bf012005-03-04 19:40:45 +00001192 if (!gbe_mem) {
1193 printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n");
1194 ret = -ENOMEM;
1195 goto out_tiles_free;
1196 }
1197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 gbe_mem_phys = (unsigned long) gbe_dma_addr;
1199 }
1200
1201#ifdef CONFIG_X86
1202 mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);
1203#endif
1204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 /* map framebuffer memory into tiles table */
1206 for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)
1207 gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;
1208
1209 info->fbops = &gbefb_ops;
1210 info->pseudo_palette = pseudo_palette;
1211 info->flags = FBINFO_DEFAULT;
1212 info->screen_base = gbe_mem;
1213 fb_alloc_cmap(&info->cmap, 256, 0);
1214
1215 /* reset GBE */
1216 gbe_reset();
1217
1218 par = info->par;
1219 /* turn on default video mode */
1220 if (fb_find_mode(&par->var, info, mode_option, NULL, 0,
1221 default_mode, 8) == 0)
1222 par->var = *default_var;
1223 info->var = par->var;
1224 gbefb_check_var(&par->var, info);
1225 gbefb_encode_fix(&info->fix, &info->var);
1226
1227 if (register_framebuffer(info) < 0) {
1228 printk(KERN_ERR "gbefb: couldn't register framebuffer\n");
1229 ret = -ENXIO;
1230 goto out_gbe_unmap;
1231 }
1232
Russell King3ae5eae2005-11-09 22:32:44 +00001233 platform_set_drvdata(p_dev, info);
1234 gbefb_create_sysfs(&p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Joe Perches31b67802013-09-19 18:35:55 -07001236 fb_info(info, "%s rev %d @ 0x%08x using %dkB memory\n",
1237 info->fix.id, gbe_revision, (unsigned)GBE_BASE,
1238 gbe_mem_size >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
1240 return 0;
1241
1242out_gbe_unmap:
1243 if (gbe_dma_addr)
1244 dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245out_tiles_free:
1246 dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
1247 (void *)gbe_tiles.cpu, gbe_tiles.dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248out_release_mem_region:
1249 release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
1250out_release_framebuffer:
1251 framebuffer_release(info);
1252
1253 return ret;
1254}
1255
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001256static int gbefb_remove(struct platform_device* p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
Russell King3ae5eae2005-11-09 22:32:44 +00001258 struct fb_info *info = platform_get_drvdata(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 unregister_framebuffer(info);
1261 gbe_turn_off();
1262 if (gbe_dma_addr)
1263 dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),
1265 (void *)gbe_tiles.cpu, gbe_tiles.dma);
1266 release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));
Joshua Kinardd3086432006-02-17 03:52:25 +00001267 gbefb_remove_sysfs(&p_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 framebuffer_release(info);
1269
1270 return 0;
1271}
1272
Russell King3ae5eae2005-11-09 22:32:44 +00001273static struct platform_driver gbefb_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 .probe = gbefb_probe,
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001275 .remove = gbefb_remove,
Russell King3ae5eae2005-11-09 22:32:44 +00001276 .driver = {
1277 .name = "gbefb",
1278 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279};
1280
Russell Kingabbf2682005-11-05 21:22:13 +00001281static struct platform_device *gbefb_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Dmitri Vorobievb6d57ae2009-03-30 22:53:26 +03001283static int __init gbefb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284{
Russell King3ae5eae2005-11-09 22:32:44 +00001285 int ret = platform_driver_register(&gbefb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (!ret) {
Russell Kingabbf2682005-11-05 21:22:13 +00001287 gbefb_device = platform_device_alloc("gbefb", 0);
1288 if (gbefb_device) {
1289 ret = platform_device_add(gbefb_device);
1290 } else {
1291 ret = -ENOMEM;
1292 }
1293 if (ret) {
1294 platform_device_put(gbefb_device);
Russell King3ae5eae2005-11-09 22:32:44 +00001295 platform_driver_unregister(&gbefb_driver);
Russell Kingabbf2682005-11-05 21:22:13 +00001296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 }
1298 return ret;
1299}
1300
Dmitri Vorobievb6d57ae2009-03-30 22:53:26 +03001301static void __exit gbefb_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
Russell Kingabbf2682005-11-05 21:22:13 +00001303 platform_device_unregister(gbefb_device);
Russell King3ae5eae2005-11-09 22:32:44 +00001304 platform_driver_unregister(&gbefb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305}
1306
1307module_init(gbefb_init);
1308module_exit(gbefb_exit);
1309
1310MODULE_LICENSE("GPL");