2 * linux/drivers/video/amba-clcd.c
4 * Copyright (C) 2001 ARM Limited, by David A Rusling
5 * Updated to 2.5, Deep Blue Solutions Ltd.
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
11 * ARM PrimeCell PL110 Color LCD Controller
13 #include <linux/dma-mapping.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/slab.h>
19 #include <linux/delay.h>
22 #include <linux/init.h>
23 #include <linux/ioport.h>
24 #include <linux/list.h>
25 #include <linux/amba/bus.h>
26 #include <linux/amba/clcd.h>
27 #include <linux/clk.h>
28 #include <linux/hardirq.h>
30 #include <asm/sizes.h>
32 #define to_clcd(info) container_of(info, struct clcd_fb, fb)
34 /* This is limited to 16 characters when displayed by X startup */
35 static const char *clcd_name
= "CLCD FB";
38 * Unfortunately, the enable/disable functions may be called either from
39 * process or IRQ context, and we _need_ to delay. This is _not_ good.
41 static inline void clcdfb_sleep(unsigned int ms
)
50 static inline void clcdfb_set_start(struct clcd_fb
*fb
)
52 unsigned long ustart
= fb
->fb
.fix
.smem_start
;
55 ustart
+= fb
->fb
.var
.yoffset
* fb
->fb
.fix
.line_length
;
56 lstart
= ustart
+ fb
->fb
.var
.yres
* fb
->fb
.fix
.line_length
/ 2;
58 writel(ustart
, fb
->regs
+ CLCD_UBAS
);
59 writel(lstart
, fb
->regs
+ CLCD_LBAS
);
62 static void clcdfb_disable(struct clcd_fb
*fb
)
66 if (fb
->board
->disable
)
67 fb
->board
->disable(fb
);
69 val
= readl(fb
->regs
+ fb
->off_cntl
);
70 if (val
& CNTL_LCDPWR
) {
72 writel(val
, fb
->regs
+ fb
->off_cntl
);
76 if (val
& CNTL_LCDEN
) {
78 writel(val
, fb
->regs
+ fb
->off_cntl
);
82 * Disable CLCD clock source.
84 if (fb
->clk_enabled
) {
85 fb
->clk_enabled
= false;
90 static void clcdfb_enable(struct clcd_fb
*fb
, u32 cntl
)
93 * Enable the CLCD clock source.
95 if (!fb
->clk_enabled
) {
96 fb
->clk_enabled
= true;
101 * Bring up by first enabling..
104 writel(cntl
, fb
->regs
+ fb
->off_cntl
);
109 * and now apply power.
112 writel(cntl
, fb
->regs
+ fb
->off_cntl
);
115 * finally, enable the interface.
117 if (fb
->board
->enable
)
118 fb
->board
->enable(fb
);
122 clcdfb_set_bitfields(struct clcd_fb
*fb
, struct fb_var_screeninfo
*var
)
127 if (fb
->panel
->caps
&& fb
->board
->caps
)
128 caps
= fb
->panel
->caps
& fb
->board
->caps
;
130 /* Old way of specifying what can be used */
131 caps
= fb
->panel
->cntl
& CNTL_BGR
?
132 CLCD_CAP_BGR
: CLCD_CAP_RGB
;
133 /* But mask out 444 modes as they weren't supported */
134 caps
&= ~CLCD_CAP_444
;
137 /* Only TFT panels can do RGB888/BGR888 */
138 if (!(fb
->panel
->cntl
& CNTL_LCDTFT
))
139 caps
&= ~CLCD_CAP_888
;
141 memset(&var
->transp
, 0, sizeof(var
->transp
));
143 var
->red
.msb_right
= 0;
144 var
->green
.msb_right
= 0;
145 var
->blue
.msb_right
= 0;
147 switch (var
->bits_per_pixel
) {
152 /* If we can't do 5551, reject */
153 caps
&= CLCD_CAP_5551
;
159 var
->red
.length
= var
->bits_per_pixel
;
161 var
->green
.length
= var
->bits_per_pixel
;
162 var
->green
.offset
= 0;
163 var
->blue
.length
= var
->bits_per_pixel
;
164 var
->blue
.offset
= 0;
168 /* If we can't do 444, 5551 or 565, reject */
169 if (!(caps
& (CLCD_CAP_444
| CLCD_CAP_5551
| CLCD_CAP_565
))) {
175 * Green length can be 4, 5 or 6 depending whether
176 * we're operating in 444, 5551 or 565 mode.
178 if (var
->green
.length
== 4 && caps
& CLCD_CAP_444
)
179 caps
&= CLCD_CAP_444
;
180 if (var
->green
.length
== 5 && caps
& CLCD_CAP_5551
)
181 caps
&= CLCD_CAP_5551
;
182 else if (var
->green
.length
== 6 && caps
& CLCD_CAP_565
)
183 caps
&= CLCD_CAP_565
;
186 * PL110 officially only supports RGB555,
187 * but may be wired up to allow RGB565.
189 if (caps
& CLCD_CAP_565
) {
190 var
->green
.length
= 6;
191 caps
&= CLCD_CAP_565
;
192 } else if (caps
& CLCD_CAP_5551
) {
193 var
->green
.length
= 5;
194 caps
&= CLCD_CAP_5551
;
196 var
->green
.length
= 4;
197 caps
&= CLCD_CAP_444
;
201 if (var
->green
.length
>= 5) {
203 var
->blue
.length
= 5;
206 var
->blue
.length
= 4;
210 /* If we can't do 888, reject */
211 caps
&= CLCD_CAP_888
;
218 var
->green
.length
= 8;
219 var
->blue
.length
= 8;
227 * >= 16bpp displays have separate colour component bitfields
228 * encoded in the pixel data. Calculate their position from
229 * the bitfield length defined above.
231 if (ret
== 0 && var
->bits_per_pixel
>= 16) {
234 bgr
= caps
& CLCD_CAP_BGR
&& var
->blue
.offset
== 0;
235 rgb
= caps
& CLCD_CAP_RGB
&& var
->red
.offset
== 0;
239 * The requested format was not possible, try just
240 * our capabilities. One of BGR or RGB must be
243 bgr
= caps
& CLCD_CAP_BGR
;
246 var
->blue
.offset
= 0;
247 var
->green
.offset
= var
->blue
.offset
+ var
->blue
.length
;
248 var
->red
.offset
= var
->green
.offset
+ var
->green
.length
;
251 var
->green
.offset
= var
->red
.offset
+ var
->red
.length
;
252 var
->blue
.offset
= var
->green
.offset
+ var
->green
.length
;
259 static int clcdfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
261 struct clcd_fb
*fb
= to_clcd(info
);
264 if (fb
->board
->check
)
265 ret
= fb
->board
->check(fb
, var
);
268 var
->xres_virtual
* var
->bits_per_pixel
/ 8 *
269 var
->yres_virtual
> fb
->fb
.fix
.smem_len
)
273 ret
= clcdfb_set_bitfields(fb
, var
);
278 static int clcdfb_set_par(struct fb_info
*info
)
280 struct clcd_fb
*fb
= to_clcd(info
);
281 struct clcd_regs regs
;
283 fb
->fb
.fix
.line_length
= fb
->fb
.var
.xres_virtual
*
284 fb
->fb
.var
.bits_per_pixel
/ 8;
286 if (fb
->fb
.var
.bits_per_pixel
<= 8)
287 fb
->fb
.fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
289 fb
->fb
.fix
.visual
= FB_VISUAL_TRUECOLOR
;
291 fb
->board
->decode(fb
, ®s
);
295 writel(regs
.tim0
, fb
->regs
+ CLCD_TIM0
);
296 writel(regs
.tim1
, fb
->regs
+ CLCD_TIM1
);
297 writel(regs
.tim2
, fb
->regs
+ CLCD_TIM2
);
298 writel(regs
.tim3
, fb
->regs
+ CLCD_TIM3
);
300 clcdfb_set_start(fb
);
302 clk_set_rate(fb
->clk
, (1000000000 / regs
.pixclock
) * 1000);
304 fb
->clcd_cntl
= regs
.cntl
;
306 clcdfb_enable(fb
, regs
.cntl
);
310 "CLCD: Registers set to\n"
311 " %08x %08x %08x %08x\n"
312 " %08x %08x %08x %08x\n",
313 readl(fb
->regs
+ CLCD_TIM0
), readl(fb
->regs
+ CLCD_TIM1
),
314 readl(fb
->regs
+ CLCD_TIM2
), readl(fb
->regs
+ CLCD_TIM3
),
315 readl(fb
->regs
+ CLCD_UBAS
), readl(fb
->regs
+ CLCD_LBAS
),
316 readl(fb
->regs
+ fb
->off_ienb
), readl(fb
->regs
+ fb
->off_cntl
));
322 static inline u32
convert_bitfield(int val
, struct fb_bitfield
*bf
)
324 unsigned int mask
= (1 << bf
->length
) - 1;
326 return (val
>> (16 - bf
->length
) & mask
) << bf
->offset
;
330 * Set a single color register. The values supplied have a 16 bit
331 * magnitude. Return != 0 for invalid regno.
334 clcdfb_setcolreg(unsigned int regno
, unsigned int red
, unsigned int green
,
335 unsigned int blue
, unsigned int transp
, struct fb_info
*info
)
337 struct clcd_fb
*fb
= to_clcd(info
);
340 fb
->cmap
[regno
] = convert_bitfield(transp
, &fb
->fb
.var
.transp
) |
341 convert_bitfield(blue
, &fb
->fb
.var
.blue
) |
342 convert_bitfield(green
, &fb
->fb
.var
.green
) |
343 convert_bitfield(red
, &fb
->fb
.var
.red
);
345 if (fb
->fb
.fix
.visual
== FB_VISUAL_PSEUDOCOLOR
&& regno
< 256) {
346 int hw_reg
= CLCD_PALETTE
+ ((regno
* 2) & ~3);
347 u32 val
, mask
, newval
;
349 newval
= (red
>> 11) & 0x001f;
350 newval
|= (green
>> 6) & 0x03e0;
351 newval
|= (blue
>> 1) & 0x7c00;
354 * 3.2.11: if we're configured for big endian
355 * byte order, the palette entries are swapped.
357 if (fb
->clcd_cntl
& CNTL_BEBO
)
367 val
= readl(fb
->regs
+ hw_reg
) & mask
;
368 writel(val
| newval
, fb
->regs
+ hw_reg
);
375 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
376 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
377 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
378 * to e.g. a video mode which doesn't support it. Implements VESA suspend
379 * and powerdown modes on hardware that supports disabling hsync/vsync:
380 * blank_mode == 2: suspend vsync
381 * blank_mode == 3: suspend hsync
382 * blank_mode == 4: powerdown
384 static int clcdfb_blank(int blank_mode
, struct fb_info
*info
)
386 struct clcd_fb
*fb
= to_clcd(info
);
388 if (blank_mode
!= 0) {
391 clcdfb_enable(fb
, fb
->clcd_cntl
);
396 static int clcdfb_mmap(struct fb_info
*info
,
397 struct vm_area_struct
*vma
)
399 struct clcd_fb
*fb
= to_clcd(info
);
400 unsigned long len
, off
= vma
->vm_pgoff
<< PAGE_SHIFT
;
403 len
= info
->fix
.smem_len
;
405 if (off
<= len
&& vma
->vm_end
- vma
->vm_start
<= len
- off
&&
407 ret
= fb
->board
->mmap(fb
, vma
);
412 static struct fb_ops clcdfb_ops
= {
413 .owner
= THIS_MODULE
,
414 .fb_check_var
= clcdfb_check_var
,
415 .fb_set_par
= clcdfb_set_par
,
416 .fb_setcolreg
= clcdfb_setcolreg
,
417 .fb_blank
= clcdfb_blank
,
418 .fb_fillrect
= cfb_fillrect
,
419 .fb_copyarea
= cfb_copyarea
,
420 .fb_imageblit
= cfb_imageblit
,
421 .fb_mmap
= clcdfb_mmap
,
424 static int clcdfb_register(struct clcd_fb
*fb
)
429 * ARM PL111 always has IENB at 0x1c; it's only PL110
430 * which is reversed on some platforms.
432 if (amba_manf(fb
->dev
) == 0x41 && amba_part(fb
->dev
) == 0x111) {
433 fb
->off_ienb
= CLCD_PL111_IENB
;
434 fb
->off_cntl
= CLCD_PL111_CNTL
;
436 #ifdef CONFIG_ARCH_VERSATILE
437 fb
->off_ienb
= CLCD_PL111_IENB
;
438 fb
->off_cntl
= CLCD_PL111_CNTL
;
440 fb
->off_ienb
= CLCD_PL110_IENB
;
441 fb
->off_cntl
= CLCD_PL110_CNTL
;
445 fb
->clk
= clk_get(&fb
->dev
->dev
, NULL
);
446 if (IS_ERR(fb
->clk
)) {
447 ret
= PTR_ERR(fb
->clk
);
451 ret
= clk_prepare(fb
->clk
);
455 fb
->fb
.device
= &fb
->dev
->dev
;
457 fb
->fb
.fix
.mmio_start
= fb
->dev
->res
.start
;
458 fb
->fb
.fix
.mmio_len
= resource_size(&fb
->dev
->res
);
460 fb
->regs
= ioremap(fb
->fb
.fix
.mmio_start
, fb
->fb
.fix
.mmio_len
);
462 printk(KERN_ERR
"CLCD: unable to remap registers\n");
467 fb
->fb
.fbops
= &clcdfb_ops
;
468 fb
->fb
.flags
= FBINFO_FLAG_DEFAULT
;
469 fb
->fb
.pseudo_palette
= fb
->cmap
;
471 strncpy(fb
->fb
.fix
.id
, clcd_name
, sizeof(fb
->fb
.fix
.id
));
472 fb
->fb
.fix
.type
= FB_TYPE_PACKED_PIXELS
;
473 fb
->fb
.fix
.type_aux
= 0;
474 fb
->fb
.fix
.xpanstep
= 0;
475 fb
->fb
.fix
.ypanstep
= 0;
476 fb
->fb
.fix
.ywrapstep
= 0;
477 fb
->fb
.fix
.accel
= FB_ACCEL_NONE
;
479 fb
->fb
.var
.xres
= fb
->panel
->mode
.xres
;
480 fb
->fb
.var
.yres
= fb
->panel
->mode
.yres
;
481 fb
->fb
.var
.xres_virtual
= fb
->panel
->mode
.xres
;
482 fb
->fb
.var
.yres_virtual
= fb
->panel
->mode
.yres
;
483 fb
->fb
.var
.bits_per_pixel
= fb
->panel
->bpp
;
484 fb
->fb
.var
.grayscale
= fb
->panel
->grayscale
;
485 fb
->fb
.var
.pixclock
= fb
->panel
->mode
.pixclock
;
486 fb
->fb
.var
.left_margin
= fb
->panel
->mode
.left_margin
;
487 fb
->fb
.var
.right_margin
= fb
->panel
->mode
.right_margin
;
488 fb
->fb
.var
.upper_margin
= fb
->panel
->mode
.upper_margin
;
489 fb
->fb
.var
.lower_margin
= fb
->panel
->mode
.lower_margin
;
490 fb
->fb
.var
.hsync_len
= fb
->panel
->mode
.hsync_len
;
491 fb
->fb
.var
.vsync_len
= fb
->panel
->mode
.vsync_len
;
492 fb
->fb
.var
.sync
= fb
->panel
->mode
.sync
;
493 fb
->fb
.var
.vmode
= fb
->panel
->mode
.vmode
;
494 fb
->fb
.var
.activate
= FB_ACTIVATE_NOW
;
495 fb
->fb
.var
.nonstd
= 0;
496 fb
->fb
.var
.height
= fb
->panel
->height
;
497 fb
->fb
.var
.width
= fb
->panel
->width
;
498 fb
->fb
.var
.accel_flags
= 0;
500 fb
->fb
.monspecs
.hfmin
= 0;
501 fb
->fb
.monspecs
.hfmax
= 100000;
502 fb
->fb
.monspecs
.vfmin
= 0;
503 fb
->fb
.monspecs
.vfmax
= 400;
504 fb
->fb
.monspecs
.dclkmin
= 1000000;
505 fb
->fb
.monspecs
.dclkmax
= 100000000;
508 * Make sure that the bitfields are set appropriately.
510 clcdfb_set_bitfields(fb
, &fb
->fb
.var
);
513 * Allocate colourmap.
515 ret
= fb_alloc_cmap(&fb
->fb
.cmap
, 256, 0);
520 * Ensure interrupts are disabled.
522 writel(0, fb
->regs
+ fb
->off_ienb
);
524 fb_set_var(&fb
->fb
, &fb
->fb
.var
);
526 dev_info(&fb
->dev
->dev
, "%s hardware, %s display\n",
527 fb
->board
->name
, fb
->panel
->mode
.name
);
529 ret
= register_framebuffer(&fb
->fb
);
533 printk(KERN_ERR
"CLCD: cannot register framebuffer (%d)\n", ret
);
535 fb_dealloc_cmap(&fb
->fb
.cmap
);
539 clk_unprepare(fb
->clk
);
546 static int clcdfb_probe(struct amba_device
*dev
, const struct amba_id
*id
)
548 struct clcd_board
*board
= dev_get_platdata(&dev
->dev
);
555 ret
= dma_set_mask_and_coherent(&dev
->dev
, DMA_BIT_MASK(32));
559 ret
= amba_request_regions(dev
, NULL
);
561 printk(KERN_ERR
"CLCD: unable to reserve regs region\n");
565 fb
= kzalloc(sizeof(struct clcd_fb
), GFP_KERNEL
);
567 printk(KERN_INFO
"CLCD: could not allocate new clcd_fb struct\n");
575 dev_info(&fb
->dev
->dev
, "PL%03x rev%u at 0x%08llx\n",
576 amba_part(dev
), amba_rev(dev
),
577 (unsigned long long)dev
->res
.start
);
579 ret
= fb
->board
->setup(fb
);
583 ret
= clcdfb_register(fb
);
585 amba_set_drvdata(dev
, fb
);
589 fb
->board
->remove(fb
);
593 amba_release_regions(dev
);
598 static int clcdfb_remove(struct amba_device
*dev
)
600 struct clcd_fb
*fb
= amba_get_drvdata(dev
);
603 unregister_framebuffer(&fb
->fb
);
605 fb_dealloc_cmap(&fb
->fb
.cmap
);
607 clk_unprepare(fb
->clk
);
610 fb
->board
->remove(fb
);
614 amba_release_regions(dev
);
619 static struct amba_id clcdfb_id_table
[] = {
627 MODULE_DEVICE_TABLE(amba
, clcdfb_id_table
);
629 static struct amba_driver clcd_driver
= {
631 .name
= "clcd-pl11x",
633 .probe
= clcdfb_probe
,
634 .remove
= clcdfb_remove
,
635 .id_table
= clcdfb_id_table
,
638 static int __init
amba_clcdfb_init(void)
640 if (fb_get_options("ambafb", NULL
))
643 return amba_driver_register(&clcd_driver
);
646 module_init(amba_clcdfb_init
);
648 static void __exit
amba_clcdfb_exit(void)
650 amba_driver_unregister(&clcd_driver
);
653 module_exit(amba_clcdfb_exit
);
655 MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
656 MODULE_LICENSE("GPL");