2 * drivers/video/ubicom32vfb.c
3 * Ubicom32 virtual frame buffer driver
5 * (C) Copyright 2009, Ubicom, Inc.
7 * This file is part of the Ubicom32 Linux Kernel Port.
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
25 * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by
29 #include <linux/device.h>
30 #include <linux/module.h>
31 #include <linux/kernel.h>
32 #include <linux/version.h>
33 #include <linux/errno.h>
34 #include <linux/string.h>
37 #include <linux/init.h>
38 #include <linux/dma-mapping.h>
39 #include <linux/platform_device.h>
40 #include <linux/device.h>
41 #include <linux/uaccess.h>
43 #define DRIVER_NAME "ubicom32vfb"
44 #define DRIVER_DESCRIPTION "Ubicom32 virtual frame buffer driver"
46 #define PALETTE_ENTRIES_NO 16
51 * vram_size: VRAM size in kilobytes, subject to alignment
53 static int vram_size
= 0;
54 module_param(vram_size
, int, 0);
55 MODULE_PARM_DESC(vram_size
, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment");
57 static int xres
= 320;
58 module_param(xres
, int, 0);
59 MODULE_PARM_DESC(xres
, "x (horizontal) resolution");
61 static int yres
= 240;
62 module_param(yres
, int, 0);
63 MODULE_PARM_DESC(yres
, "y (vertical) resolution");
66 module_param(bgr
, int, 0);
67 MODULE_PARM_DESC(bgr
, "display is BGR (Blue is MSB)");
69 #define BITS_PER_PIXEL 16
72 * Buffer alignment, must not be 0
74 #define UBICOM32VFB_ALIGNMENT 4
77 * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in.
79 static struct fb_fix_screeninfo ubicom32vfb_fix
= {
81 .type
= FB_TYPE_PACKED_PIXELS
,
82 .visual
= FB_VISUAL_TRUECOLOR
,
83 .accel
= FB_ACCEL_UBICOM32_VFB
,
87 * Filled in at probe time when we find out what the hardware supports
89 static struct fb_var_screeninfo ubicom32vfb_var
;
92 * Private data structure
94 struct ubicom32vfb_drvdata
{
95 struct fb_info
*fbinfo
;
99 * The address of the framebuffer in memory
105 * Total size of vram including alignment allowance
110 * Fake palette of 16 colors
112 u32 pseudo_palette
[PALETTE_ENTRIES_NO
];
115 static struct platform_device
*ubicom32vfb_platform_device
;
118 * ubicom32vfb_pan_display
119 * Pans the display to a given location. Supports only y direction panning.
121 static int ubicom32vfb_pan_display(struct fb_var_screeninfo
*var
, struct fb_info
*fbi
)
123 struct ubicom32vfb_drvdata
*ud
= (struct ubicom32vfb_drvdata
*)fbi
->par
;
127 * Get the last y line that would be displayed. Since we don't support YWRAP,
128 * it must be less than our virtual y size.
130 u32 lasty
= var
->yoffset
+ var
->yres
;
131 if (lasty
> fbi
->var
.yres_virtual
) {
133 * We would fall off the end of our frame buffer if we panned here.
140 * We don't support panning in the x direction
146 * Everything looks sane, go ahead and pan
148 * We have to calculate a new address for the VDC to look at
150 new_addr
= ud
->fb_aligned
+ (var
->yoffset
* fbi
->fix
.line_length
);
156 * ubicom32vfb_setcolreg
157 * Sets a color in our virtual palette
159 static int ubicom32vfb_setcolreg(unsigned regno
, unsigned red
, unsigned green
, unsigned blue
, unsigned transp
, struct fb_info
*fbi
)
161 u32
*palette
= fbi
->pseudo_palette
;
163 if (regno
>= PALETTE_ENTRIES_NO
) {
168 * We only use 8 bits from each color
175 * Convert any grayscale values
177 if (fbi
->var
.grayscale
) {
178 u16 gray
= red
+ green
+ blue
;
179 gray
+= (gray
>> 2) + (gray
>> 3) - (gray
>> 7);
189 palette
[regno
] = (red
<< fbi
->var
.red
.offset
) | (green
<< fbi
->var
.green
.offset
) |
190 (blue
<< fbi
->var
.blue
.offset
);
198 static int ubicom32vfb_mmap(struct fb_info
*info
, struct vm_area_struct
*vma
)
200 struct ubicom32vfb_drvdata
*ud
= (struct ubicom32vfb_drvdata
*)info
->par
;
202 vma
->vm_start
= (unsigned long)(ud
->fb_aligned
);
204 vma
->vm_end
= vma
->vm_start
+ info
->fix
.smem_len
;
206 /* For those who don't understand how mmap works, go read
207 * Documentation/nommu-mmap.txt.
208 * For those that do, you will know that the VM_MAYSHARE flag
209 * must be set in the vma->vm_flags structure on noMMU
210 * Other flags can be set, and are documented in
214 vma
->vm_flags
|= VM_MAYSHARE
| VM_SHARED
;
220 * ubicom32vfb_check_var
221 * Check the var, tweak it but don't change operational parameters.
223 static int ubicom32vfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
225 struct ubicom32vfb_drvdata
*ud
= (struct ubicom32vfb_drvdata
*)info
->par
;
226 u32 line_size
= var
->xres
* (BITS_PER_PIXEL
/ 8);
229 * See if we can handle this bpp
231 if (var
->bits_per_pixel
> BITS_PER_PIXEL
) {
234 var
->bits_per_pixel
= BITS_PER_PIXEL
;
237 * See if we have enough memory to handle this resolution
239 if ((line_size
* var
->yres
* BITS_PER_PIXEL
/ 8) > ud
->total_vram_size
) {
243 var
->xres_virtual
= var
->xres
;
244 var
->yres_virtual
= ud
->total_vram_size
/ line_size
;
247 var
->green
.length
= 6;
248 var
->green
.offset
= 5;
249 var
->blue
.length
= 5;
250 var
->transp
.offset
= var
->transp
.length
= 0;
254 var
->blue
.offset
= 11;
256 var
->red
.offset
= 11;
257 var
->blue
.offset
= 0;
263 var
->vmode
= FB_VMODE_NONINTERLACED
;
270 * ubicom32vfb_set_par
271 * Set the video mode according to info->var
273 static int ubicom32vfb_set_par(struct fb_info
*info
)
278 if ((xres
== info
->var
.xres
) && (yres
== info
->var
.yres
)) {
285 xres
= info
->var
.xres
;
286 yres
= info
->var
.yres
;
287 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
288 info
->fix
.xpanstep
= 0;
289 info
->fix
.ypanstep
= 1;
290 info
->fix
.line_length
= xres
* (BITS_PER_PIXEL
/ 8);
297 * List of supported operations
299 static struct fb_ops ubicom32vfb_ops
=
301 .owner
= THIS_MODULE
,
302 .fb_pan_display
= ubicom32vfb_pan_display
,
303 .fb_setcolreg
= ubicom32vfb_setcolreg
,
304 .fb_mmap
= ubicom32vfb_mmap
,
305 .fb_check_var
= ubicom32vfb_check_var
,
306 .fb_set_par
= ubicom32vfb_set_par
,
307 .fb_fillrect
= cfb_fillrect
,
308 .fb_copyarea
= cfb_copyarea
,
309 .fb_imageblit
= cfb_imageblit
,
313 * ubicom32vfb_release
315 static int ubicom32vfb_release(struct device
*dev
)
317 struct ubicom32vfb_drvdata
*ud
= dev_get_drvdata(dev
);
319 unregister_framebuffer(ud
->fbinfo
);
321 if (ud
->cmap_alloc
) {
322 fb_dealloc_cmap(&ud
->fbinfo
->cmap
);
329 framebuffer_release(ud
->fbinfo
);
330 dev_set_drvdata(dev
, NULL
);
336 * ubicom32vfb_platform_probe
338 static int __init
ubicom32vfb_platform_probe(struct platform_device
*pdev
)
340 struct ubicom32vfb_drvdata
*ud
;
341 struct fb_info
*fbinfo
;
344 struct device
*dev
= &pdev
->dev
;
348 * This is the minimum VRAM size
350 fbsize
= xres
* yres
* 2;
352 vram_size
= (fbsize
+ 1023) / 1024;
354 if (fbsize
> (vram_size
* 1024)) {
355 dev_err(dev
, "Not enough VRAM for display, need >= %u bytes\n", fbsize
);
356 return -ENOMEM
; // should be ebadparam?
361 * Allocate the framebuffer instance + our private data
363 fbinfo
= framebuffer_alloc(sizeof(struct ubicom32vfb_drvdata
), &pdev
->dev
);
365 dev_err(dev
, "Not enough memory to allocate instance.\n");
370 * Fill in our private data.
372 ud
= (struct ubicom32vfb_drvdata
*)fbinfo
->par
;
374 dev_set_drvdata(dev
, ud
);
377 * Allocate and align the requested amount of VRAM
379 ud
->total_vram_size
= (vram_size
* 1024) + UBICOM32VFB_ALIGNMENT
;
380 ud
->fb
= kmalloc(ud
->total_vram_size
, GFP_KERNEL
);
381 if (ud
->fb
== NULL
) {
382 dev_err(dev
, "Couldn't allocate VRAM\n");
387 offset
= (u32_t
)ud
->fb
& (UBICOM32VFB_ALIGNMENT
- 1);
389 ud
->fb_aligned
= ud
->fb
;
391 offset
= UBICOM32VFB_ALIGNMENT
- offset
;
392 ud
->fb_aligned
= ud
->fb
+ offset
;
396 * Clear the entire frame buffer
398 memset(ud
->fb_aligned
, 0, vram_size
* 1024);
401 * Fill in the fb_var_screeninfo structure
403 memset(&ubicom32vfb_var
, 0, sizeof(ubicom32vfb_var
));
404 ubicom32vfb_var
.bits_per_pixel
= BITS_PER_PIXEL
;
405 ubicom32vfb_var
.red
.length
= 5;
406 ubicom32vfb_var
.green
.length
= 6;
407 ubicom32vfb_var
.green
.offset
= 5;
408 ubicom32vfb_var
.blue
.length
= 5;
409 ubicom32vfb_var
.activate
= FB_ACTIVATE_NOW
;
412 ubicom32vfb_var
.red
.offset
= 0;
413 ubicom32vfb_var
.blue
.offset
= 11;
415 ubicom32vfb_var
.red
.offset
= 11;
416 ubicom32vfb_var
.blue
.offset
= 0;
420 * Fill in the fb_info structure
422 ud
->fbinfo
->device
= dev
;
423 ud
->fbinfo
->screen_base
= (void *)ud
->fb_aligned
;
424 ud
->fbinfo
->fbops
= &ubicom32vfb_ops
;
425 ud
->fbinfo
->fix
= ubicom32vfb_fix
;
426 ud
->fbinfo
->fix
.smem_start
= (u32
)ud
->fb_aligned
;
427 ud
->fbinfo
->fix
.smem_len
= vram_size
* 1024;
428 ud
->fbinfo
->fix
.line_length
= xres
* 2;
429 ud
->fbinfo
->fix
.mmio_start
= (u32
)ud
;
430 ud
->fbinfo
->fix
.mmio_len
= sizeof(struct ubicom32vfb_drvdata
);
433 * We support panning in the y direction only
435 ud
->fbinfo
->fix
.xpanstep
= 0;
436 ud
->fbinfo
->fix
.ypanstep
= 1;
438 ud
->fbinfo
->pseudo_palette
= ud
->pseudo_palette
;
439 ud
->fbinfo
->flags
= FBINFO_DEFAULT
;
440 ud
->fbinfo
->var
= ubicom32vfb_var
;
441 ud
->fbinfo
->var
.xres
= xres
;
442 ud
->fbinfo
->var
.yres
= yres
;
445 * We cannot pan in the X direction, so xres_virtual is xres
446 * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length
448 ud
->fbinfo
->var
.xres_virtual
= xres
;
449 ud
->fbinfo
->var
.yres_virtual
= (vram_size
* 1024) / ud
->fbinfo
->fix
.line_length
;
452 * Allocate a color map
454 rc
= fb_alloc_cmap(&ud
->fbinfo
->cmap
, PALETTE_ENTRIES_NO
, 0);
456 dev_err(dev
, "Fail to allocate colormap (%d entries)\n",
460 ud
->cmap_alloc
= true;
463 * Register new frame buffer
465 rc
= register_framebuffer(ud
->fbinfo
);
467 dev_err(dev
, "Could not register frame buffer\n");
472 * Tell the log we are here
474 dev_info(dev
, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n",
475 ud
->fb
, ud
->fb_aligned
, vram_size
, ud
->fbinfo
->var
.xres
, ud
->fbinfo
->var
.yres
,
476 ud
->fbinfo
->var
.xres_virtual
, ud
->fbinfo
->var
.yres_virtual
);
484 ubicom32vfb_release(dev
);
489 * ubicom32vfb_platform_remove
491 static int ubicom32vfb_platform_remove(struct platform_device
*pdev
)
493 dev_info(&(pdev
->dev
), "Ubicom32 FB Driver Remove\n");
494 return ubicom32vfb_release(&pdev
->dev
);
497 static struct platform_driver ubicom32vfb_platform_driver
= {
498 .probe
= ubicom32vfb_platform_probe
,
499 .remove
= ubicom32vfb_platform_remove
,
502 .owner
= THIS_MODULE
,
509 * Process kernel boot options
511 static int __init
ubicom32vfb_setup(char *options
)
515 if (!options
|| !*options
) {
519 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
524 if (!strncmp(this_opt
, "vram_size=", 10)) {
525 vram_size
= simple_strtoul(this_opt
+ 10, NULL
, 0);
529 if (!strncmp(this_opt
, "bgr=", 4)) {
530 bgr
= simple_strtoul(this_opt
+ 4, NULL
, 0);
534 if (!strncmp(this_opt
, "xres=", 5)) {
535 xres
= simple_strtoul(this_opt
+ 5, NULL
, 0);
539 if (!strncmp(this_opt
, "yres=", 5)) {
540 yres
= simple_strtoul(this_opt
+ 5, NULL
, 0);
551 static int __devinit
ubicom32vfb_init(void)
557 * Get kernel boot options (in 'video=ubicom32vfb:<options>')
561 if (fb_get_options(DRIVER_NAME
, &option
)) {
564 ubicom32vfb_setup(option
);
567 ret
= platform_driver_register(&ubicom32vfb_platform_driver
);
569 #ifdef CONFIG_FB_UBICOM32_VIRTUAL_NOAUTO
573 ubicom32vfb_platform_device
= platform_device_alloc(DRIVER_NAME
, 0);
575 if (ubicom32vfb_platform_device
)
576 ret
= platform_device_add(ubicom32vfb_platform_device
);
581 platform_device_put(ubicom32vfb_platform_device
);
582 platform_driver_unregister(&ubicom32vfb_platform_driver
);
589 module_init(ubicom32vfb_init
);
594 static void __exit
ubicom32vfb_exit(void)
596 platform_device_unregister(ubicom32vfb_platform_device
);
597 platform_driver_unregister(&ubicom32vfb_platform_driver
);
599 module_exit(ubicom32vfb_exit
);
601 MODULE_LICENSE("GPL");
602 MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
603 MODULE_DESCRIPTION(DRIVER_DESCRIPTION
);