2 * Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
4 * 2011 (c) Aeroflex Gaisler AB
6 * Full documentation of the core can be found here:
7 * http://www.gaisler.com/products/grlib/grip.pdf
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
14 * Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
18 #include <linux/platform_device.h>
19 #include <linux/dma-mapping.h>
20 #include <linux/of_platform.h>
21 #include <linux/of_device.h>
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/string.h>
25 #include <linux/delay.h>
26 #include <linux/errno.h>
27 #include <linux/init.h>
28 #include <linux/slab.h>
29 #include <linux/tty.h>
35 u32 status
; /* 0x00 */
36 u32 video_length
; /* 0x04 */
37 u32 front_porch
; /* 0x08 */
38 u32 sync_length
; /* 0x0C */
39 u32 line_length
; /* 0x10 */
40 u32 fb_pos
; /* 0x14 */
41 u32 clk_vector
[4]; /* 0x18 */
46 struct grvga_regs
*regs
;
47 u32 color_palette
[16]; /* 16 entry pseudo palette used by fbcon in true color mode */
49 int fb_alloced
; /* = 1 if framebuffer is allocated in main memory */
53 static const struct fb_videomode grvga_modedb
[] = {
56 NULL
, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
57 0, FB_VMODE_NONINTERLACED
60 NULL
, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
61 0, FB_VMODE_NONINTERLACED
64 NULL
, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
65 0, FB_VMODE_NONINTERLACED
67 /* 1024x768 @ 60 Hz */
68 NULL
, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
69 0, FB_VMODE_NONINTERLACED
73 static const struct fb_fix_screeninfo grvga_fix
= {
75 .type
= FB_TYPE_PACKED_PIXELS
,
76 .visual
= FB_VISUAL_PSEUDOCOLOR
,
80 .accel
= FB_ACCEL_NONE
,
83 static int grvga_check_var(struct fb_var_screeninfo
*var
,
86 struct grvga_par
*par
= info
->par
;
93 if (var
->bits_per_pixel
<= 8)
94 var
->bits_per_pixel
= 8;
95 else if (var
->bits_per_pixel
<= 16)
96 var
->bits_per_pixel
= 16;
97 else if (var
->bits_per_pixel
<= 24)
98 var
->bits_per_pixel
= 24;
99 else if (var
->bits_per_pixel
<= 32)
100 var
->bits_per_pixel
= 32;
104 var
->xres_virtual
= var
->xres
;
105 var
->yres_virtual
= 2*var
->yres
;
107 if (info
->fix
.smem_len
) {
108 if ((var
->yres_virtual
*var
->xres_virtual
*var
->bits_per_pixel
/8) > info
->fix
.smem_len
)
112 /* Which clocks that are available can be read out in these registers */
113 for (i
= 0; i
<= 3 ; i
++) {
114 if (var
->pixclock
== par
->regs
->clk_vector
[i
])
122 switch (info
->var
.bits_per_pixel
) {
124 var
->red
= (struct fb_bitfield
) {0, 8, 0}; /* offset, length, msb-right */
125 var
->green
= (struct fb_bitfield
) {0, 8, 0};
126 var
->blue
= (struct fb_bitfield
) {0, 8, 0};
127 var
->transp
= (struct fb_bitfield
) {0, 0, 0};
130 var
->red
= (struct fb_bitfield
) {11, 5, 0};
131 var
->green
= (struct fb_bitfield
) {5, 6, 0};
132 var
->blue
= (struct fb_bitfield
) {0, 5, 0};
133 var
->transp
= (struct fb_bitfield
) {0, 0, 0};
137 var
->red
= (struct fb_bitfield
) {16, 8, 0};
138 var
->green
= (struct fb_bitfield
) {8, 8, 0};
139 var
->blue
= (struct fb_bitfield
) {0, 8, 0};
140 var
->transp
= (struct fb_bitfield
) {24, 8, 0};
149 static int grvga_set_par(struct fb_info
*info
)
153 struct grvga_par
*par
= info
->par
;
155 __raw_writel(((info
->var
.yres
- 1) << 16) | (info
->var
.xres
- 1),
156 &par
->regs
->video_length
);
158 __raw_writel((info
->var
.lower_margin
<< 16) | (info
->var
.right_margin
),
159 &par
->regs
->front_porch
);
161 __raw_writel((info
->var
.vsync_len
<< 16) | (info
->var
.hsync_len
),
162 &par
->regs
->sync_length
);
164 __raw_writel(((info
->var
.yres
+ info
->var
.lower_margin
+ info
->var
.upper_margin
+ info
->var
.vsync_len
- 1) << 16) |
165 (info
->var
.xres
+ info
->var
.right_margin
+ info
->var
.left_margin
+ info
->var
.hsync_len
- 1),
166 &par
->regs
->line_length
);
168 switch (info
->var
.bits_per_pixel
) {
170 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
174 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
179 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
186 __raw_writel((par
->clk_sel
<< 6) | (func
<< 4) | 1,
189 info
->fix
.line_length
= (info
->var
.xres_virtual
*info
->var
.bits_per_pixel
)/8;
193 static int grvga_setcolreg(unsigned regno
, unsigned red
, unsigned green
, unsigned blue
, unsigned transp
, struct fb_info
*info
)
195 struct grvga_par
*par
;
198 if (regno
>= 256) /* Size of CLUT */
201 if (info
->var
.grayscale
) {
202 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
203 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
208 #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
210 red
= CNVT_TOHW(red
, info
->var
.red
.length
);
211 green
= CNVT_TOHW(green
, info
->var
.green
.length
);
212 blue
= CNVT_TOHW(blue
, info
->var
.blue
.length
);
213 transp
= CNVT_TOHW(transp
, info
->var
.transp
.length
);
217 /* In PSEUDOCOLOR we use the hardware CLUT */
218 if (info
->fix
.visual
== FB_VISUAL_PSEUDOCOLOR
)
219 __raw_writel((regno
<< 24) | (red
<< 16) | (green
<< 8) | blue
,
222 /* Truecolor uses the pseudo palette */
223 else if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
229 v
= (red
<< info
->var
.red
.offset
) |
230 (green
<< info
->var
.green
.offset
) |
231 (blue
<< info
->var
.blue
.offset
) |
232 (transp
<< info
->var
.transp
.offset
);
234 ((u32
*) (info
->pseudo_palette
))[regno
] = v
;
239 static int grvga_pan_display(struct fb_var_screeninfo
*var
,
240 struct fb_info
*info
)
242 struct grvga_par
*par
= info
->par
;
243 struct fb_fix_screeninfo
*fix
= &info
->fix
;
246 if (var
->xoffset
!= 0)
249 base_addr
= fix
->smem_start
+ (var
->yoffset
* fix
->line_length
);
252 /* Set framebuffer base address */
253 __raw_writel(base_addr
,
259 static struct fb_ops grvga_ops
= {
260 .owner
= THIS_MODULE
,
261 .fb_check_var
= grvga_check_var
,
262 .fb_set_par
= grvga_set_par
,
263 .fb_setcolreg
= grvga_setcolreg
,
264 .fb_pan_display
= grvga_pan_display
,
265 .fb_fillrect
= cfb_fillrect
,
266 .fb_copyarea
= cfb_copyarea
,
267 .fb_imageblit
= cfb_imageblit
270 static int grvga_parse_custom(char *options
,
271 struct fb_var_screeninfo
*screendata
)
275 if (!options
|| !*options
)
278 while ((this_opt
= strsep(&options
, " ")) != NULL
) {
284 screendata
->pixclock
= simple_strtoul(this_opt
, NULL
, 0);
288 screendata
->xres
= screendata
->xres_virtual
= simple_strtoul(this_opt
, NULL
, 0);
292 screendata
->right_margin
= simple_strtoul(this_opt
, NULL
, 0);
296 screendata
->hsync_len
= simple_strtoul(this_opt
, NULL
, 0);
300 screendata
->left_margin
= simple_strtoul(this_opt
, NULL
, 0);
304 screendata
->yres
= screendata
->yres_virtual
= simple_strtoul(this_opt
, NULL
, 0);
308 screendata
->lower_margin
= simple_strtoul(this_opt
, NULL
, 0);
312 screendata
->vsync_len
= simple_strtoul(this_opt
, NULL
, 0);
316 screendata
->upper_margin
= simple_strtoul(this_opt
, NULL
, 0);
320 screendata
->bits_per_pixel
= simple_strtoul(this_opt
, NULL
, 0);
327 screendata
->activate
= FB_ACTIVATE_NOW
;
328 screendata
->vmode
= FB_VMODE_NONINTERLACED
;
332 static int grvga_probe(struct platform_device
*dev
)
334 struct fb_info
*info
;
335 int retval
= -ENOMEM
;
336 unsigned long virtual_start
;
337 unsigned long grvga_fix_addr
= 0;
338 unsigned long physical_start
= 0;
339 unsigned long grvga_mem_size
= 0;
340 struct grvga_par
*par
= NULL
;
341 char *options
= NULL
, *mode_opt
= NULL
;
343 info
= framebuffer_alloc(sizeof(struct grvga_par
), &dev
->dev
);
345 dev_err(&dev
->dev
, "framebuffer_alloc failed\n");
349 /* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
351 * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
352 * If address is left out, we allocate memory,
353 * if size is left out we only allocate enough to support the given mode.
355 if (fb_get_options("grvga", &options
)) {
360 if (!options
|| !*options
)
361 options
= "640x480-8@60";
364 char *this_opt
= strsep(&options
, ",");
369 if (!strncmp(this_opt
, "custom", 6)) {
370 if (grvga_parse_custom(this_opt
, &info
->var
) < 0) {
371 dev_err(&dev
->dev
, "Failed to parse custom mode (%s).\n", this_opt
);
375 } else if (!strncmp(this_opt
, "addr", 4))
376 grvga_fix_addr
= simple_strtoul(this_opt
+ 5, NULL
, 16);
377 else if (!strncmp(this_opt
, "size", 4))
378 grvga_mem_size
= simple_strtoul(this_opt
+ 5, NULL
, 0);
384 info
->fbops
= &grvga_ops
;
385 info
->fix
= grvga_fix
;
386 info
->pseudo_palette
= par
->color_palette
;
387 info
->flags
= FBINFO_DEFAULT
| FBINFO_PARTIAL_PAN_OK
| FBINFO_HWACCEL_YPAN
;
388 info
->fix
.smem_len
= grvga_mem_size
;
390 if (!devm_request_mem_region(&dev
->dev
, dev
->resource
[0].start
,
391 resource_size(&dev
->resource
[0]), "grlib-svgactrl regs")) {
392 dev_err(&dev
->dev
, "registers already mapped\n");
397 par
->regs
= of_ioremap(&dev
->resource
[0], 0,
398 resource_size(&dev
->resource
[0]),
399 "grlib-svgactrl regs");
402 dev_err(&dev
->dev
, "failed to map registers\n");
407 retval
= fb_alloc_cmap(&info
->cmap
, 256, 0);
409 dev_err(&dev
->dev
, "failed to allocate mem with fb_alloc_cmap\n");
415 retval
= fb_find_mode(&info
->var
, info
, mode_opt
,
416 grvga_modedb
, sizeof(grvga_modedb
), &grvga_modedb
[0], 8);
417 if (!retval
|| retval
== 4) {
424 grvga_mem_size
= info
->var
.xres_virtual
* info
->var
.yres_virtual
* info
->var
.bits_per_pixel
/8;
426 if (grvga_fix_addr
) {
427 /* Got framebuffer base address from argument list */
429 physical_start
= grvga_fix_addr
;
431 if (!devm_request_mem_region(&dev
->dev
, physical_start
,
432 grvga_mem_size
, dev
->name
)) {
433 dev_err(&dev
->dev
, "failed to request memory region\n");
438 virtual_start
= (unsigned long) ioremap(physical_start
, grvga_mem_size
);
440 if (!virtual_start
) {
441 dev_err(&dev
->dev
, "error mapping framebuffer memory\n");
445 } else { /* Allocate frambuffer memory */
449 virtual_start
= (unsigned long) __get_free_pages(GFP_DMA
,
450 get_order(grvga_mem_size
));
451 if (!virtual_start
) {
453 "unable to allocate framebuffer memory (%lu bytes)\n",
459 physical_start
= dma_map_single(&dev
->dev
, (void *)virtual_start
, grvga_mem_size
, DMA_TO_DEVICE
);
461 /* Set page reserved so that mmap will work. This is necessary
462 * since we'll be remapping normal memory.
464 for (page
= virtual_start
;
465 page
< PAGE_ALIGN(virtual_start
+ grvga_mem_size
);
467 SetPageReserved(virt_to_page(page
));
473 memset((unsigned long *) virtual_start
, 0, grvga_mem_size
);
475 info
->screen_base
= (char __iomem
*) virtual_start
;
476 info
->fix
.smem_start
= physical_start
;
477 info
->fix
.smem_len
= grvga_mem_size
;
479 dev_set_drvdata(&dev
->dev
, info
);
482 "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n",
483 info
->node
, info
->var
.xres
, info
->var
.yres
, info
->var
.bits_per_pixel
,
484 grvga_mem_size
>> 10, info
->screen_base
);
486 retval
= register_framebuffer(info
);
488 dev_err(&dev
->dev
, "failed to register framebuffer\n");
492 __raw_writel(physical_start
, &par
->regs
->fb_pos
);
493 __raw_writel(__raw_readl(&par
->regs
->status
) | 1, /* Enable framebuffer */
500 iounmap((void *)virtual_start
);
502 kfree((void *)virtual_start
);
504 fb_dealloc_cmap(&info
->cmap
);
506 of_iounmap(&dev
->resource
[0], par
->regs
,
507 resource_size(&dev
->resource
[0]));
509 framebuffer_release(info
);
514 static int grvga_remove(struct platform_device
*device
)
516 struct fb_info
*info
= dev_get_drvdata(&device
->dev
);
517 struct grvga_par
*par
;
521 unregister_framebuffer(info
);
522 fb_dealloc_cmap(&info
->cmap
);
524 of_iounmap(&device
->resource
[0], par
->regs
,
525 resource_size(&device
->resource
[0]));
527 if (!par
->fb_alloced
)
528 iounmap(info
->screen_base
);
530 kfree((void *)info
->screen_base
);
532 framebuffer_release(info
);
538 static struct of_device_id svgactrl_of_match
[] = {
540 .name
= "GAISLER_SVGACTRL",
547 MODULE_DEVICE_TABLE(of
, svgactrl_of_match
);
549 static struct platform_driver grvga_driver
= {
551 .name
= "grlib-svgactrl",
552 .of_match_table
= svgactrl_of_match
,
554 .probe
= grvga_probe
,
555 .remove
= grvga_remove
,
558 module_platform_driver(grvga_driver
);
560 MODULE_LICENSE("GPL");
561 MODULE_AUTHOR("Aeroflex Gaisler");
562 MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");