2 * drivers/video/ubicom32plio80.c
3 * Ubicom32 80 bus PLIO 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/interrupt.h>
39 #include <linux/dma-mapping.h>
40 #include <linux/platform_device.h>
41 #include <linux/device.h>
42 #include <linux/uaccess.h>
45 #define DRIVER_NAME "ubicom32plio80"
46 #define DRIVER_DESCRIPTION "Ubicom32 80 bus PLIO frame buffer driver"
48 #define PALETTE_ENTRIES_NO 16
53 * vram_size: VRAM size in kilobytes, subject to alignment
55 static int vram_size
= 0;
56 module_param(vram_size
, int, 0);
57 MODULE_PARM_DESC(vram_size
, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment");
59 static int xres
= 240;
60 module_param(xres
, int, 0);
61 MODULE_PARM_DESC(xres
, "x (horizontal) resolution");
63 static int yres
= 320;
64 module_param(yres
, int, 0);
65 MODULE_PARM_DESC(yres
, "y (vertical) resolution");
68 module_param(bgr
, int, 0);
69 MODULE_PARM_DESC(bgr
, "display is BGR (Blue is MSB)");
71 #define BITS_PER_PIXEL 16
74 * Buffer alignment, must not be 0
76 #define UBICOM32PLIO80_ALIGNMENT 4
80 * 16-bit data bus on port I
84 static const plio_fctl_t plio_fctl
= {
86 .ptif_port_mode
= PLIO_PORT_MODE_DI
,
91 .ecif_extclk_ena
= 0, // enable clock output on PD7 table 2.65/p111 says extctl[0]?
92 .icif_clk_src_sel
= PLIO_CLK_IO
,
101 static const plio_config_t plio_config
= {
106 .grpsel
[0] = {1,1,1,1,1,1,1,1,1,1},
109 * Table 12.66 Counter load value
111 .cs_lut
[0] = {0,0,0,0,0,0,0,0},
114 * Table 2.75 PLIO PFSM Configuration Registers
117 .extctl_o_lut
[0] = {0x3f, 0x2f, 0x3f, 0x3f},
119 .extctl_o_lut
[1] = {0x3f, 0x3f, 0x3f, 0x2f},
125 .output_ena
= (1 << 6) | (1 << 4),
129 static const u32_t ubicom32plio80_plio_fsm
[] = {
131 0x00070007, 0x00070007,
132 0x00070007, 0x00070007,
133 0x00070007, 0x00070007,
134 0x00070007, 0x00070007,
136 0x16260806, 0x16260806,
137 0x16260806, 0x16260806,
138 0x16260806, 0x16260806,
139 0x16260806, 0x16260806,
142 0x22061806, 0x22061806,
143 0x22061806, 0x22061806,
144 0x22061806, 0x22061806,
145 0x22061806, 0x22061806,
147 0x22061806, 0x22061806,
148 0x22061806, 0x22061806,
149 0x22061806, 0x22061806,
150 0x22061806, 0x22061806,
153 0x00070806, 0x00070806,
154 0x00070806, 0x00070806,
155 0x00070806, 0x00070806,
156 0x00070806, 0x00070806,
158 0x00070806, 0x00070806,
159 0x00070806, 0x00070806,
160 0x00070806, 0x00070806,
161 0x00070806, 0x00070806,
165 * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in.
167 static struct fb_fix_screeninfo ubicom32plio80_fix
= {
169 .type
= FB_TYPE_PACKED_PIXELS
,
170 .visual
= FB_VISUAL_TRUECOLOR
,
171 .accel
= FB_ACCEL_UBICOM32_PLIO80
,
175 * Filled in at probe time when we find out what the hardware supports
177 static struct fb_var_screeninfo ubicom32plio80_var
;
180 * Private data structure
182 struct ubicom32plio80_drvdata
{
183 struct fb_info
*fbinfo
;
187 * The address of the framebuffer in memory
193 * Total size of vram including alignment allowance
198 * Fake palette of 16 colors
200 u32 pseudo_palette
[PALETTE_ENTRIES_NO
];
205 * Current pointer and bytes left to transfer with the PLIO
212 static struct platform_device
*ubicom32plio80_platform_device
;
217 static int ubicom32plio80_isr(int irq
, void *appdata
)
219 struct ubicom32plio80_drvdata
*ud
= (struct ubicom32plio80_drvdata
*)appdata
;
221 if (!ud
->bytes_to_xfer
) {
222 ubicom32_disable_interrupt(TX_FIFO_INT(PLIO_PORT
));
223 PLIO_NBR
->intmask
.txfifo_wm
= 0;
230 "move.4 (%[fifo]), (%[data])4++ \n\t"
232 : [data
] "+a" (ud
->xfer_ptr
)
233 : [fifo
] "a" (&PLIO_NBR
->tx_lo
)
236 ud
->bytes_to_xfer
-= 32;
242 * ubicom32plio80_update
244 static void ubicom32plio80_update(struct ubicom32plio80_drvdata
*ud
, u32
*fb
)
246 struct ubicom32_io_port
*ri
= (struct ubicom32_io_port
*)RI
;
247 struct ubicom32_io_port
*rd
= (struct ubicom32_io_port
*)RD
;
250 ud
->bytes_to_xfer
= (xres
* yres
* 2) - 64;
254 rd
->gpio_mask
&= ~((1 << 4) | (1 << 2));
256 *(u32
*)(&PLIO_NBR
->intclr
) = ~0;
257 PLIO_NBR
->intmask
.txfifo_wm
= 1;
258 PLIO_NBR
->fifo_wm
.tx
= 8;
259 ubicom32_enable_interrupt(TX_FIFO_INT(PLIO_PORT
));
263 "move.4 (%[fifo]), (%[data])4++ \n\t"
265 : [data
] "+a" (ud
->xfer_ptr
)
266 : [fifo
] "a" (&PLIO_NBR
->tx_lo
)
271 * ubicom32plio80_pan_display
272 * Pans the display to a given location. Supports only y direction panning.
274 static int ubicom32plio80_pan_display(struct fb_var_screeninfo
*var
, struct fb_info
*fbi
)
276 struct ubicom32plio80_drvdata
*ud
= (struct ubicom32plio80_drvdata
*)fbi
->par
;
280 * Get the last y line that would be displayed. Since we don't support YWRAP,
281 * it must be less than our virtual y size.
283 u32 lasty
= var
->yoffset
+ var
->yres
;
284 if (lasty
> fbi
->var
.yres_virtual
) {
286 * We would fall off the end of our frame buffer if we panned here.
293 * We don't support panning in the x direction
299 * Everything looks sane, go ahead and pan
301 * We have to calculate a new address for the VDC to look at
303 new_addr
= ud
->fb_aligned
+ (var
->yoffset
* fbi
->fix
.line_length
);
309 * ubicom32plio80_setcolreg
310 * Sets a color in our virtual palette
312 static int ubicom32plio80_setcolreg(unsigned regno
, unsigned red
, unsigned green
, unsigned blue
, unsigned transp
, struct fb_info
*fbi
)
314 u32
*palette
= fbi
->pseudo_palette
;
316 if (regno
>= PALETTE_ENTRIES_NO
) {
321 * We only use 8 bits from each color
328 * Convert any grayscale values
330 if (fbi
->var
.grayscale
) {
331 u16 gray
= red
+ green
+ blue
;
332 gray
+= (gray
>> 2) + (gray
>> 3) - (gray
>> 7);
342 palette
[regno
] = (red
<< fbi
->var
.red
.offset
) | (green
<< fbi
->var
.green
.offset
) |
343 (blue
<< fbi
->var
.blue
.offset
);
349 * ubicom32plio80_mmap
351 static int ubicom32plio80_mmap(struct fb_info
*info
, struct vm_area_struct
*vma
)
353 struct ubicom32plio80_drvdata
*ud
= (struct ubicom32plio80_drvdata
*)info
->par
;
355 vma
->vm_start
= (unsigned long)(ud
->fb_aligned
);
357 vma
->vm_end
= vma
->vm_start
+ info
->fix
.smem_len
;
359 /* For those who don't understand how mmap works, go read
360 * Documentation/nommu-mmap.txt.
361 * For those that do, you will know that the VM_MAYSHARE flag
362 * must be set in the vma->vm_flags structure on noMMU
363 * Other flags can be set, and are documented in
367 vma
->vm_flags
|= VM_MAYSHARE
| VM_SHARED
;
373 * ubicom32plio80_check_var
374 * Check the var, tweak it but don't change operational parameters.
376 static int ubicom32plio80_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
378 struct ubicom32plio80_drvdata
*ud
= (struct ubicom32plio80_drvdata
*)info
->par
;
379 u32 line_size
= var
->xres
* (BITS_PER_PIXEL
/ 8);
382 * See if we can handle this bpp
384 if (var
->bits_per_pixel
> BITS_PER_PIXEL
) {
387 var
->bits_per_pixel
= BITS_PER_PIXEL
;
390 * See if we have enough memory to handle this resolution
392 if ((line_size
* var
->yres
* BITS_PER_PIXEL
/ 8) > ud
->total_vram_size
) {
396 var
->xres_virtual
= var
->xres
;
397 var
->yres_virtual
= ud
->total_vram_size
/ line_size
;
400 var
->green
.length
= 6;
401 var
->green
.offset
= 5;
402 var
->blue
.length
= 5;
403 var
->transp
.offset
= var
->transp
.length
= 0;
407 var
->blue
.offset
= 11;
409 var
->red
.offset
= 11;
410 var
->blue
.offset
= 0;
416 var
->vmode
= FB_VMODE_NONINTERLACED
;
423 * ubicom32plio80_set_par
424 * Set the video mode according to info->var
426 static int ubicom32plio80_set_par(struct fb_info
*info
)
431 if ((xres
== info
->var
.xres
) && (yres
== info
->var
.yres
)) {
438 xres
= info
->var
.xres
;
439 yres
= info
->var
.yres
;
440 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
441 info
->fix
.xpanstep
= 0;
442 info
->fix
.ypanstep
= 1;
443 info
->fix
.line_length
= xres
* (BITS_PER_PIXEL
/ 8);
450 * List of supported operations
452 static struct fb_ops ubicom32plio80_ops
=
454 .owner
= THIS_MODULE
,
455 .fb_pan_display
= ubicom32plio80_pan_display
,
456 .fb_setcolreg
= ubicom32plio80_setcolreg
,
457 .fb_mmap
= ubicom32plio80_mmap
,
458 .fb_check_var
= ubicom32plio80_check_var
,
459 .fb_set_par
= ubicom32plio80_set_par
,
460 .fb_fillrect
= cfb_fillrect
,
461 .fb_copyarea
= cfb_copyarea
,
462 .fb_imageblit
= cfb_imageblit
,
466 * ubicom32plio80_release
468 static int ubicom32plio80_release(struct device
*dev
)
470 struct ubicom32plio80_drvdata
*ud
= dev_get_drvdata(dev
);
472 unregister_framebuffer(ud
->fbinfo
);
475 free_irq(TX_FIFO_INT(PLIO_PORT
), ud
);
477 if (ud
->cmap_alloc
) {
478 fb_dealloc_cmap(&ud
->fbinfo
->cmap
);
485 framebuffer_release(ud
->fbinfo
);
486 dev_set_drvdata(dev
, NULL
);
492 * ubicom32plio80_platform_probe
494 static int __init
ubicom32plio80_platform_probe(struct platform_device
*pdev
)
496 struct ubicom32plio80_drvdata
*ud
;
497 struct fb_info
*fbinfo
;
500 struct device
*dev
= &pdev
->dev
;
504 * This is the minimum VRAM size
506 fbsize
= xres
* yres
* 2;
508 vram_size
= (fbsize
+ 1023) / 1024;
510 if (fbsize
> (vram_size
* 1024)) {
511 dev_err(dev
, "Not enough VRAM for display, need >= %u bytes\n", fbsize
);
512 return -ENOMEM
; // should be ebadparam?
517 * Allocate the framebuffer instance + our private data
519 fbinfo
= framebuffer_alloc(sizeof(struct ubicom32plio80_drvdata
), &pdev
->dev
);
521 dev_err(dev
, "Not enough memory to allocate instance.\n");
526 * Fill in our private data.
528 ud
= (struct ubicom32plio80_drvdata
*)fbinfo
->par
;
530 dev_set_drvdata(dev
, ud
);
533 * Allocate and align the requested amount of VRAM
535 ud
->total_vram_size
= (vram_size
* 1024) + UBICOM32PLIO80_ALIGNMENT
;
536 ud
->fb
= kmalloc(ud
->total_vram_size
, GFP_KERNEL
);
537 if (ud
->fb
== NULL
) {
538 dev_err(dev
, "Couldn't allocate VRAM\n");
543 offset
= (u32_t
)ud
->fb
& (UBICOM32PLIO80_ALIGNMENT
- 1);
545 ud
->fb_aligned
= ud
->fb
;
547 offset
= UBICOM32PLIO80_ALIGNMENT
- offset
;
548 ud
->fb_aligned
= ud
->fb
+ offset
;
552 * Clear the entire frame buffer
554 memset(ud
->fb_aligned
, 0, vram_size
* 1024);
557 * Fill in the fb_var_screeninfo structure
559 memset(&ubicom32plio80_var
, 0, sizeof(ubicom32plio80_var
));
560 ubicom32plio80_var
.bits_per_pixel
= BITS_PER_PIXEL
;
561 ubicom32plio80_var
.red
.length
= 5;
562 ubicom32plio80_var
.green
.length
= 6;
563 ubicom32plio80_var
.green
.offset
= 5;
564 ubicom32plio80_var
.blue
.length
= 5;
565 ubicom32plio80_var
.activate
= FB_ACTIVATE_NOW
;
568 ubicom32plio80_var
.red
.offset
= 0;
569 ubicom32plio80_var
.blue
.offset
= 11;
571 ubicom32plio80_var
.red
.offset
= 11;
572 ubicom32plio80_var
.blue
.offset
= 0;
576 * Fill in the fb_info structure
578 ud
->fbinfo
->device
= dev
;
579 ud
->fbinfo
->screen_base
= (void *)ud
->fb_aligned
;
580 ud
->fbinfo
->fbops
= &ubicom32plio80_ops
;
581 ud
->fbinfo
->fix
= ubicom32plio80_fix
;
582 ud
->fbinfo
->fix
.smem_start
= (u32
)ud
->fb_aligned
;
583 ud
->fbinfo
->fix
.smem_len
= vram_size
* 1024;
584 ud
->fbinfo
->fix
.line_length
= xres
* 2;
585 ud
->fbinfo
->fix
.mmio_start
= (u32
)ud
;
586 ud
->fbinfo
->fix
.mmio_len
= sizeof(struct ubicom32plio80_drvdata
);
589 * We support panning in the y direction only
591 ud
->fbinfo
->fix
.xpanstep
= 0;
592 ud
->fbinfo
->fix
.ypanstep
= 1;
594 ud
->fbinfo
->pseudo_palette
= ud
->pseudo_palette
;
595 ud
->fbinfo
->flags
= FBINFO_DEFAULT
;
596 ud
->fbinfo
->var
= ubicom32plio80_var
;
597 ud
->fbinfo
->var
.xres
= xres
;
598 ud
->fbinfo
->var
.yres
= yres
;
601 * We cannot pan in the X direction, so xres_virtual is xres
602 * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length
604 ud
->fbinfo
->var
.xres_virtual
= xres
;
605 ud
->fbinfo
->var
.yres_virtual
= (vram_size
* 1024) / ud
->fbinfo
->fix
.line_length
;
608 * Allocate a color map
610 rc
= fb_alloc_cmap(&ud
->fbinfo
->cmap
, PALETTE_ENTRIES_NO
, 0);
612 dev_err(dev
, "Fail to allocate colormap (%d entries)\n",
616 ud
->cmap_alloc
= true;
619 * Register new frame buffer
621 rc
= register_framebuffer(ud
->fbinfo
);
623 dev_err(dev
, "Could not register frame buffer\n");
628 * request the PLIO IRQ
630 rc
= request_irq(TX_FIFO_INT(PLIO_PORT
), ubicom32plio80_isr
, IRQF_DISABLED
, "ubicom32plio80", ud
);
632 dev_err(dev
, "Could not request IRQ\n");
638 * Clear any garbage out of the TX FIFOs (idif_txfifo_flush)
640 * cast through ubicom32_io_port to make sure the compiler does a word write
642 ((struct ubicom32_io_port
*)PLIO_NBR
)->int_set
= (1 << 18);
645 * Start up the state machine
647 plio_init(&plio_fctl
, &plio_config
, (plio_sram_t
*)ubicom32plio80_plio_fsm
, sizeof(ubicom32plio80_plio_fsm
));
648 PLIO_NBR
->fctl0
.pfsm_cmd
= 0;
650 ubicom32plio80_update(ud
, ud
->fb_aligned
);
653 * Tell the log we are here
655 dev_info(dev
, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n",
656 ud
->fb
, ud
->fb_aligned
, vram_size
, ud
->fbinfo
->var
.xres
, ud
->fbinfo
->var
.yres
,
657 ud
->fbinfo
->var
.xres_virtual
, ud
->fbinfo
->var
.yres_virtual
);
665 ubicom32plio80_release(dev
);
670 * ubicom32plio80_platform_remove
672 static int ubicom32plio80_platform_remove(struct platform_device
*pdev
)
674 dev_info(&(pdev
->dev
), "Ubicom32 FB Driver Remove\n");
675 return ubicom32plio80_release(&pdev
->dev
);
678 static struct platform_driver ubicom32plio80_platform_driver
= {
679 .probe
= ubicom32plio80_platform_probe
,
680 .remove
= ubicom32plio80_platform_remove
,
683 .owner
= THIS_MODULE
,
689 * ubicom32plio80_setup
690 * Process kernel boot options
692 static int __init
ubicom32plio80_setup(char *options
)
696 if (!options
|| !*options
) {
700 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
705 if (!strncmp(this_opt
, "vram_size=", 10)) {
706 vram_size
= simple_strtoul(this_opt
+ 10, NULL
, 0);
710 if (!strncmp(this_opt
, "bgr=", 4)) {
711 bgr
= simple_strtoul(this_opt
+ 4, NULL
, 0);
715 if (!strncmp(this_opt
, "xres=", 5)) {
716 xres
= simple_strtoul(this_opt
+ 5, NULL
, 0);
720 if (!strncmp(this_opt
, "yres=", 5)) {
721 yres
= simple_strtoul(this_opt
+ 5, NULL
, 0);
730 * ubicom32plio80_init
732 static int __devinit
ubicom32plio80_init(void)
738 * Get kernel boot options (in 'video=ubicom32plio80:<options>')
742 if (fb_get_options(DRIVER_NAME
, &option
)) {
745 ubicom32plio80_setup(option
);
748 ret
= platform_driver_register(&ubicom32plio80_platform_driver
);
751 ubicom32plio80_platform_device
= platform_device_alloc(DRIVER_NAME
, 0);
753 if (ubicom32plio80_platform_device
)
754 ret
= platform_device_add(ubicom32plio80_platform_device
);
759 platform_device_put(ubicom32plio80_platform_device
);
760 platform_driver_unregister(&ubicom32plio80_platform_driver
);
766 module_init(ubicom32plio80_init
);
769 * ubicom32plio80_exit
771 static void __exit
ubicom32plio80_exit(void)
773 platform_device_unregister(ubicom32plio80_platform_device
);
774 platform_driver_unregister(&ubicom32plio80_platform_driver
);
776 module_exit(ubicom32plio80_exit
);
778 MODULE_LICENSE("GPL");
779 MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
780 MODULE_DESCRIPTION(DRIVER_DESCRIPTION
);