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