2 * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller
4 * Copyright (C) 2008 Marvell International Ltd.
7 * 2009-02-16 adapted from original version for PXA168/910
8 * Jun Nie <njun@marvell.com>
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file COPYING in the main directory of this archive for
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/string.h>
19 #include <linux/interrupt.h>
20 #include <linux/slab.h>
22 #include <linux/delay.h>
23 #include <linux/init.h>
25 #include <linux/ioport.h>
26 #include <linux/platform_device.h>
27 #include <linux/dma-mapping.h>
28 #include <linux/clk.h>
29 #include <linux/err.h>
30 #include <linux/uaccess.h>
31 #include <video/pxa168fb.h>
35 #define DEFAULT_REFRESH 60 /* Hz */
37 static int determine_best_pix_fmt(struct fb_var_screeninfo
*var
)
42 if (var
->bits_per_pixel
== 8)
43 return PIX_FMT_PSEUDOCOLOR
;
48 if (var
->bits_per_pixel
== 16 && var
->red
.length
<= 5 &&
49 var
->green
.length
<= 6 && var
->blue
.length
<= 5) {
50 if (var
->transp
.length
== 0) {
51 if (var
->red
.offset
>= var
->blue
.offset
)
52 return PIX_FMT_RGB565
;
54 return PIX_FMT_BGR565
;
57 if (var
->transp
.length
== 1 && var
->green
.length
<= 5) {
58 if (var
->red
.offset
>= var
->blue
.offset
)
59 return PIX_FMT_RGB1555
;
61 return PIX_FMT_BGR1555
;
68 if (var
->bits_per_pixel
<= 32 && var
->red
.length
<= 8 &&
69 var
->green
.length
<= 8 && var
->blue
.length
<= 8) {
70 if (var
->bits_per_pixel
== 24 && var
->transp
.length
== 0) {
71 if (var
->red
.offset
>= var
->blue
.offset
)
72 return PIX_FMT_RGB888PACK
;
74 return PIX_FMT_BGR888PACK
;
77 if (var
->bits_per_pixel
== 32 && var
->transp
.length
== 8) {
78 if (var
->red
.offset
>= var
->blue
.offset
)
79 return PIX_FMT_RGBA888
;
81 return PIX_FMT_BGRA888
;
83 if (var
->red
.offset
>= var
->blue
.offset
)
84 return PIX_FMT_RGB888UNPACK
;
86 return PIX_FMT_BGR888UNPACK
;
93 static void set_pix_fmt(struct fb_var_screeninfo
*var
, int pix_fmt
)
97 var
->bits_per_pixel
= 16;
98 var
->red
.offset
= 11; var
->red
.length
= 5;
99 var
->green
.offset
= 5; var
->green
.length
= 6;
100 var
->blue
.offset
= 0; var
->blue
.length
= 5;
101 var
->transp
.offset
= 0; var
->transp
.length
= 0;
104 var
->bits_per_pixel
= 16;
105 var
->red
.offset
= 0; var
->red
.length
= 5;
106 var
->green
.offset
= 5; var
->green
.length
= 6;
107 var
->blue
.offset
= 11; var
->blue
.length
= 5;
108 var
->transp
.offset
= 0; var
->transp
.length
= 0;
110 case PIX_FMT_RGB1555
:
111 var
->bits_per_pixel
= 16;
112 var
->red
.offset
= 10; var
->red
.length
= 5;
113 var
->green
.offset
= 5; var
->green
.length
= 5;
114 var
->blue
.offset
= 0; var
->blue
.length
= 5;
115 var
->transp
.offset
= 15; var
->transp
.length
= 1;
117 case PIX_FMT_BGR1555
:
118 var
->bits_per_pixel
= 16;
119 var
->red
.offset
= 0; var
->red
.length
= 5;
120 var
->green
.offset
= 5; var
->green
.length
= 5;
121 var
->blue
.offset
= 10; var
->blue
.length
= 5;
122 var
->transp
.offset
= 15; var
->transp
.length
= 1;
124 case PIX_FMT_RGB888PACK
:
125 var
->bits_per_pixel
= 24;
126 var
->red
.offset
= 16; var
->red
.length
= 8;
127 var
->green
.offset
= 8; var
->green
.length
= 8;
128 var
->blue
.offset
= 0; var
->blue
.length
= 8;
129 var
->transp
.offset
= 0; var
->transp
.length
= 0;
131 case PIX_FMT_BGR888PACK
:
132 var
->bits_per_pixel
= 24;
133 var
->red
.offset
= 0; var
->red
.length
= 8;
134 var
->green
.offset
= 8; var
->green
.length
= 8;
135 var
->blue
.offset
= 16; var
->blue
.length
= 8;
136 var
->transp
.offset
= 0; var
->transp
.length
= 0;
138 case PIX_FMT_RGBA888
:
139 var
->bits_per_pixel
= 32;
140 var
->red
.offset
= 16; var
->red
.length
= 8;
141 var
->green
.offset
= 8; var
->green
.length
= 8;
142 var
->blue
.offset
= 0; var
->blue
.length
= 8;
143 var
->transp
.offset
= 24; var
->transp
.length
= 8;
145 case PIX_FMT_BGRA888
:
146 var
->bits_per_pixel
= 32;
147 var
->red
.offset
= 0; var
->red
.length
= 8;
148 var
->green
.offset
= 8; var
->green
.length
= 8;
149 var
->blue
.offset
= 16; var
->blue
.length
= 8;
150 var
->transp
.offset
= 24; var
->transp
.length
= 8;
152 case PIX_FMT_PSEUDOCOLOR
:
153 var
->bits_per_pixel
= 8;
154 var
->red
.offset
= 0; var
->red
.length
= 8;
155 var
->green
.offset
= 0; var
->green
.length
= 8;
156 var
->blue
.offset
= 0; var
->blue
.length
= 8;
157 var
->transp
.offset
= 0; var
->transp
.length
= 0;
162 static void set_mode(struct pxa168fb_info
*fbi
, struct fb_var_screeninfo
*var
,
163 struct fb_videomode
*mode
, int pix_fmt
, int ystretch
)
165 struct fb_info
*info
= fbi
->info
;
167 set_pix_fmt(var
, pix_fmt
);
169 var
->xres
= mode
->xres
;
170 var
->yres
= mode
->yres
;
171 var
->xres_virtual
= max(var
->xres
, var
->xres_virtual
);
173 var
->yres_virtual
= info
->fix
.smem_len
/
174 (var
->xres_virtual
* (var
->bits_per_pixel
>> 3));
176 var
->yres_virtual
= max(var
->yres
, var
->yres_virtual
);
178 var
->accel_flags
= FB_ACCEL_NONE
;
179 var
->pixclock
= mode
->pixclock
;
180 var
->left_margin
= mode
->left_margin
;
181 var
->right_margin
= mode
->right_margin
;
182 var
->upper_margin
= mode
->upper_margin
;
183 var
->lower_margin
= mode
->lower_margin
;
184 var
->hsync_len
= mode
->hsync_len
;
185 var
->vsync_len
= mode
->vsync_len
;
186 var
->sync
= mode
->sync
;
187 var
->vmode
= FB_VMODE_NONINTERLACED
;
188 var
->rotate
= FB_ROTATE_UR
;
191 static int pxa168fb_check_var(struct fb_var_screeninfo
*var
,
192 struct fb_info
*info
)
194 struct pxa168fb_info
*fbi
= info
->par
;
198 * Determine which pixel format we're going to use.
200 pix_fmt
= determine_best_pix_fmt(var
);
203 set_pix_fmt(var
, pix_fmt
);
204 fbi
->pix_fmt
= pix_fmt
;
207 * Basic geometry sanity checks.
209 if (var
->xoffset
+ var
->xres
> var
->xres_virtual
)
211 if (var
->yoffset
+ var
->yres
> var
->yres_virtual
)
213 if (var
->xres
+ var
->right_margin
+
214 var
->hsync_len
+ var
->left_margin
> 2048)
216 if (var
->yres
+ var
->lower_margin
+
217 var
->vsync_len
+ var
->upper_margin
> 2048)
221 * Check size of framebuffer.
223 if (var
->xres_virtual
* var
->yres_virtual
*
224 (var
->bits_per_pixel
>> 3) > info
->fix
.smem_len
)
231 * The hardware clock divider has an integer and a fractional
234 * clk2 = clk_in / integer_divider
235 * clk_out = clk2 * (1 - (fractional_divider >> 12))
237 * Calculate integer and fractional divider for given clk_in
240 static void set_clock_divider(struct pxa168fb_info
*fbi
,
241 const struct fb_videomode
*m
)
249 * Notice: The field pixclock is used by linux fb
250 * is in pixel second. E.g. struct fb_videomode &
251 * struct fb_var_screeninfo
255 * Check input values.
257 if (!m
|| !m
->pixclock
|| !m
->refresh
) {
258 dev_err(fbi
->dev
, "Input refresh or pixclock is wrong.\n");
263 * Using PLL/AXI clock.
268 * Calc divider according to refresh rate.
270 div_result
= 1000000000000ll;
271 do_div(div_result
, m
->pixclock
);
272 needed_pixclk
= (u32
)div_result
;
274 divider_int
= clk_get_rate(fbi
->clk
) / needed_pixclk
;
276 /* check whether divisor is too small. */
277 if (divider_int
< 2) {
278 dev_warn(fbi
->dev
, "Warning: clock source is too slow. "
279 "Try smaller resolution\n");
284 * Set setting to reg.
287 writel(x
, fbi
->reg_base
+ LCD_CFG_SCLK_DIV
);
290 static void set_dma_control0(struct pxa168fb_info
*fbi
)
295 * Set bit to enable graphics DMA.
297 x
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
298 x
&= ~CFG_GRA_ENA_MASK
;
299 x
|= fbi
->active
? CFG_GRA_ENA(1) : CFG_GRA_ENA(0);
302 * If we are in a pseudo-color mode, we need to enable
305 if (fbi
->pix_fmt
== PIX_FMT_PSEUDOCOLOR
)
309 * Configure hardware pixel format.
312 x
|= (fbi
->pix_fmt
>> 1) << 16;
315 * Check red and blue pixel swap.
316 * 1. source data swap
317 * 2. panel output data swap
320 x
|= ((fbi
->pix_fmt
& 1) ^ (fbi
->panel_rbswap
)) << 12;
322 writel(x
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
325 static void set_dma_control1(struct pxa168fb_info
*fbi
, int sync
)
330 * Configure default bits: vsync triggers DMA, gated clock
331 * enable, power save enable, configure alpha registers to
332 * display 100% graphics, and set pixel command.
334 x
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL1
);
338 * We trigger DMA on the falling edge of vsync if vsync is
339 * active low, or on the rising edge if vsync is active high.
341 if (!(sync
& FB_SYNC_VERT_HIGH_ACT
))
344 writel(x
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL1
);
347 static void set_graphics_start(struct fb_info
*info
, int xoffset
, int yoffset
)
349 struct pxa168fb_info
*fbi
= info
->par
;
350 struct fb_var_screeninfo
*var
= &info
->var
;
354 pixel_offset
= (yoffset
* var
->xres_virtual
) + xoffset
;
356 addr
= fbi
->fb_start_dma
+ (pixel_offset
* (var
->bits_per_pixel
>> 3));
357 writel(addr
, fbi
->reg_base
+ LCD_CFG_GRA_START_ADDR0
);
360 static void set_dumb_panel_control(struct fb_info
*info
)
362 struct pxa168fb_info
*fbi
= info
->par
;
363 struct pxa168fb_mach_info
*mi
= dev_get_platdata(fbi
->dev
);
367 * Preserve enable flag.
369 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
) & 0x00000001;
371 x
|= (fbi
->is_blanked
? 0x7 : mi
->dumb_mode
) << 28;
372 x
|= mi
->gpio_output_data
<< 20;
373 x
|= mi
->gpio_output_mask
<< 12;
374 x
|= mi
->panel_rgb_reverse_lanes
? 0x00000080 : 0;
375 x
|= mi
->invert_composite_blank
? 0x00000040 : 0;
376 x
|= (info
->var
.sync
& FB_SYNC_COMP_HIGH_ACT
) ? 0x00000020 : 0;
377 x
|= mi
->invert_pix_val_ena
? 0x00000010 : 0;
378 x
|= (info
->var
.sync
& FB_SYNC_VERT_HIGH_ACT
) ? 0 : 0x00000008;
379 x
|= (info
->var
.sync
& FB_SYNC_HOR_HIGH_ACT
) ? 0 : 0x00000004;
380 x
|= mi
->invert_pixclock
? 0x00000002 : 0;
382 writel(x
, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
385 static void set_dumb_screen_dimensions(struct fb_info
*info
)
387 struct pxa168fb_info
*fbi
= info
->par
;
388 struct fb_var_screeninfo
*v
= &info
->var
;
392 x
= v
->xres
+ v
->right_margin
+ v
->hsync_len
+ v
->left_margin
;
393 y
= v
->yres
+ v
->lower_margin
+ v
->vsync_len
+ v
->upper_margin
;
395 writel((y
<< 16) | x
, fbi
->reg_base
+ LCD_SPUT_V_H_TOTAL
);
398 static int pxa168fb_set_par(struct fb_info
*info
)
400 struct pxa168fb_info
*fbi
= info
->par
;
401 struct fb_var_screeninfo
*var
= &info
->var
;
402 struct fb_videomode mode
;
406 * Set additional mode info.
408 if (fbi
->pix_fmt
== PIX_FMT_PSEUDOCOLOR
)
409 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
411 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
412 info
->fix
.line_length
= var
->xres_virtual
* var
->bits_per_pixel
/ 8;
413 info
->fix
.ypanstep
= var
->yres
;
416 * Disable panel output while we setup the display.
418 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
419 writel(x
& ~1, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
422 * Configure global panel parameters.
424 writel((var
->yres
<< 16) | var
->xres
,
425 fbi
->reg_base
+ LCD_SPU_V_H_ACTIVE
);
428 * convet var to video mode
430 fb_var_to_videomode(&mode
, &info
->var
);
432 /* Calculate clock divisor. */
433 set_clock_divider(fbi
, &mode
);
435 /* Configure dma ctrl regs. */
436 set_dma_control0(fbi
);
437 set_dma_control1(fbi
, info
->var
.sync
);
440 * Configure graphics DMA parameters.
442 x
= readl(fbi
->reg_base
+ LCD_CFG_GRA_PITCH
);
443 x
= (x
& ~0xFFFF) | ((var
->xres_virtual
* var
->bits_per_pixel
) >> 3);
444 writel(x
, fbi
->reg_base
+ LCD_CFG_GRA_PITCH
);
445 writel((var
->yres
<< 16) | var
->xres
,
446 fbi
->reg_base
+ LCD_SPU_GRA_HPXL_VLN
);
447 writel((var
->yres
<< 16) | var
->xres
,
448 fbi
->reg_base
+ LCD_SPU_GZM_HPXL_VLN
);
451 * Configure dumb panel ctrl regs & timings.
453 set_dumb_panel_control(info
);
454 set_dumb_screen_dimensions(info
);
456 writel((var
->left_margin
<< 16) | var
->right_margin
,
457 fbi
->reg_base
+ LCD_SPU_H_PORCH
);
458 writel((var
->upper_margin
<< 16) | var
->lower_margin
,
459 fbi
->reg_base
+ LCD_SPU_V_PORCH
);
462 * Re-enable panel output.
464 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
465 writel(x
| 1, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
470 static unsigned int chan_to_field(unsigned int chan
, struct fb_bitfield
*bf
)
472 return ((chan
& 0xffff) >> (16 - bf
->length
)) << bf
->offset
;
475 static u32
to_rgb(u16 red
, u16 green
, u16 blue
)
481 return (red
<< 16) | (green
<< 8) | blue
;
485 pxa168fb_setcolreg(unsigned int regno
, unsigned int red
, unsigned int green
,
486 unsigned int blue
, unsigned int trans
, struct fb_info
*info
)
488 struct pxa168fb_info
*fbi
= info
->par
;
491 if (info
->var
.grayscale
)
492 red
= green
= blue
= (19595 * red
+ 38470 * green
+
495 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
&& regno
< 16) {
496 val
= chan_to_field(red
, &info
->var
.red
);
497 val
|= chan_to_field(green
, &info
->var
.green
);
498 val
|= chan_to_field(blue
, &info
->var
.blue
);
499 fbi
->pseudo_palette
[regno
] = val
;
502 if (info
->fix
.visual
== FB_VISUAL_PSEUDOCOLOR
&& regno
< 256) {
503 val
= to_rgb(red
, green
, blue
);
504 writel(val
, fbi
->reg_base
+ LCD_SPU_SRAM_WRDAT
);
505 writel(0x8300 | regno
, fbi
->reg_base
+ LCD_SPU_SRAM_CTRL
);
511 static int pxa168fb_blank(int blank
, struct fb_info
*info
)
513 struct pxa168fb_info
*fbi
= info
->par
;
515 fbi
->is_blanked
= (blank
== FB_BLANK_UNBLANK
) ? 0 : 1;
516 set_dumb_panel_control(info
);
521 static int pxa168fb_pan_display(struct fb_var_screeninfo
*var
,
522 struct fb_info
*info
)
524 set_graphics_start(info
, var
->xoffset
, var
->yoffset
);
529 static irqreturn_t
pxa168fb_handle_irq(int irq
, void *dev_id
)
531 struct pxa168fb_info
*fbi
= dev_id
;
532 u32 isr
= readl(fbi
->reg_base
+ SPU_IRQ_ISR
);
534 if ((isr
& GRA_FRAME_IRQ0_ENA_MASK
)) {
536 writel(isr
& (~GRA_FRAME_IRQ0_ENA_MASK
),
537 fbi
->reg_base
+ SPU_IRQ_ISR
);
544 static const struct fb_ops pxa168fb_ops
= {
545 .owner
= THIS_MODULE
,
546 .fb_check_var
= pxa168fb_check_var
,
547 .fb_set_par
= pxa168fb_set_par
,
548 .fb_setcolreg
= pxa168fb_setcolreg
,
549 .fb_blank
= pxa168fb_blank
,
550 .fb_pan_display
= pxa168fb_pan_display
,
551 .fb_fillrect
= cfb_fillrect
,
552 .fb_copyarea
= cfb_copyarea
,
553 .fb_imageblit
= cfb_imageblit
,
556 static void pxa168fb_init_mode(struct fb_info
*info
,
557 struct pxa168fb_mach_info
*mi
)
559 struct pxa168fb_info
*fbi
= info
->par
;
560 struct fb_var_screeninfo
*var
= &info
->var
;
561 u32 total_w
, total_h
, refresh
;
563 const struct fb_videomode
*m
;
568 refresh
= DEFAULT_REFRESH
;
570 /* try to find best video mode. */
571 m
= fb_find_best_mode(&info
->var
, &info
->modelist
);
573 fb_videomode_to_var(&info
->var
, m
);
576 var
->xres_virtual
= var
->xres
;
577 var
->yres_virtual
= info
->fix
.smem_len
/
578 (var
->xres_virtual
* (var
->bits_per_pixel
>> 3));
579 dev_dbg(fbi
->dev
, "pxa168fb: find best mode: res = %dx%d\n",
580 var
->xres
, var
->yres
);
582 /* correct pixclock. */
583 total_w
= var
->xres
+ var
->left_margin
+ var
->right_margin
+
585 total_h
= var
->yres
+ var
->upper_margin
+ var
->lower_margin
+
588 div_result
= 1000000000000ll;
589 do_div(div_result
, total_w
* total_h
* refresh
);
590 var
->pixclock
= (u32
)div_result
;
593 static int pxa168fb_probe(struct platform_device
*pdev
)
595 struct pxa168fb_mach_info
*mi
;
596 struct fb_info
*info
= 0;
597 struct pxa168fb_info
*fbi
= 0;
598 struct resource
*res
;
602 mi
= dev_get_platdata(&pdev
->dev
);
604 dev_err(&pdev
->dev
, "no platform data defined\n");
608 clk
= devm_clk_get(&pdev
->dev
, "LCDCLK");
610 dev_err(&pdev
->dev
, "unable to get LCDCLK");
614 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
616 dev_err(&pdev
->dev
, "no IO memory defined\n");
620 irq
= platform_get_irq(pdev
, 0);
622 dev_err(&pdev
->dev
, "no IRQ defined\n");
626 info
= framebuffer_alloc(sizeof(struct pxa168fb_info
), &pdev
->dev
);
631 /* Initialize private data */
635 fbi
->dev
= info
->dev
= &pdev
->dev
;
636 fbi
->panel_rbswap
= mi
->panel_rbswap
;
638 fbi
->active
= mi
->active
;
641 * Initialise static fb parameters.
643 info
->flags
= FBINFO_DEFAULT
| FBINFO_PARTIAL_PAN_OK
|
644 FBINFO_HWACCEL_XPAN
| FBINFO_HWACCEL_YPAN
;
646 strlcpy(info
->fix
.id
, mi
->id
, 16);
647 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
648 info
->fix
.type_aux
= 0;
649 info
->fix
.xpanstep
= 0;
650 info
->fix
.ypanstep
= 0;
651 info
->fix
.ywrapstep
= 0;
652 info
->fix
.mmio_start
= res
->start
;
653 info
->fix
.mmio_len
= resource_size(res
);
654 info
->fix
.accel
= FB_ACCEL_NONE
;
655 info
->fbops
= &pxa168fb_ops
;
656 info
->pseudo_palette
= fbi
->pseudo_palette
;
659 * Map LCD controller registers.
661 fbi
->reg_base
= devm_ioremap(&pdev
->dev
, res
->start
,
663 if (fbi
->reg_base
== NULL
) {
665 goto failed_free_info
;
669 * Allocate framebuffer memory.
671 info
->fix
.smem_len
= PAGE_ALIGN(DEFAULT_FB_SIZE
);
673 info
->screen_base
= dma_alloc_wc(fbi
->dev
, info
->fix
.smem_len
,
674 &fbi
->fb_start_dma
, GFP_KERNEL
);
675 if (info
->screen_base
== NULL
) {
677 goto failed_free_info
;
680 info
->fix
.smem_start
= (unsigned long)fbi
->fb_start_dma
;
681 set_graphics_start(info
, 0, 0);
684 * Set video mode according to platform data.
686 set_mode(fbi
, &info
->var
, mi
->modes
, mi
->pix_fmt
, 1);
688 fb_videomode_to_modelist(mi
->modes
, mi
->num_modes
, &info
->modelist
);
691 * init video mode data.
693 pxa168fb_init_mode(info
, mi
);
696 * Fill in sane defaults.
698 ret
= pxa168fb_check_var(&info
->var
, info
);
700 goto failed_free_fbmem
;
703 * enable controller clock
705 clk_prepare_enable(fbi
->clk
);
707 pxa168fb_set_par(info
);
710 * Configure default register values.
712 writel(0, fbi
->reg_base
+ LCD_SPU_BLANKCOLOR
);
713 writel(mi
->io_pin_allocation_mode
, fbi
->reg_base
+ SPU_IOPAD_CONTROL
);
714 writel(0, fbi
->reg_base
+ LCD_CFG_GRA_START_ADDR1
);
715 writel(0, fbi
->reg_base
+ LCD_SPU_GRA_OVSA_HPXL_VLN
);
716 writel(0, fbi
->reg_base
+ LCD_SPU_SRAM_PARA0
);
717 writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
718 fbi
->reg_base
+ LCD_SPU_SRAM_PARA1
);
721 * Allocate color map.
723 if (fb_alloc_cmap(&info
->cmap
, 256, 0) < 0) {
725 goto failed_free_clk
;
729 * Register irq handler.
731 ret
= devm_request_irq(&pdev
->dev
, irq
, pxa168fb_handle_irq
,
732 IRQF_SHARED
, info
->fix
.id
, fbi
);
734 dev_err(&pdev
->dev
, "unable to request IRQ\n");
736 goto failed_free_cmap
;
740 * Enable GFX interrupt
742 writel(GRA_FRAME_IRQ0_ENA(0x1), fbi
->reg_base
+ SPU_IRQ_ENA
);
745 * Register framebuffer.
747 ret
= register_framebuffer(info
);
749 dev_err(&pdev
->dev
, "Failed to register pxa168-fb: %d\n", ret
);
751 goto failed_free_cmap
;
754 platform_set_drvdata(pdev
, fbi
);
758 fb_dealloc_cmap(&info
->cmap
);
760 clk_disable_unprepare(fbi
->clk
);
762 dma_free_wc(fbi
->dev
, info
->fix
.smem_len
,
763 info
->screen_base
, fbi
->fb_start_dma
);
765 framebuffer_release(info
);
767 dev_err(&pdev
->dev
, "frame buffer device init failed with %d\n", ret
);
771 static int pxa168fb_remove(struct platform_device
*pdev
)
773 struct pxa168fb_info
*fbi
= platform_get_drvdata(pdev
);
774 struct fb_info
*info
;
780 /* disable DMA transfer */
781 data
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
782 data
&= ~CFG_GRA_ENA_MASK
;
783 writel(data
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
787 unregister_framebuffer(info
);
789 writel(GRA_FRAME_IRQ0_ENA(0x0), fbi
->reg_base
+ SPU_IRQ_ENA
);
792 fb_dealloc_cmap(&info
->cmap
);
794 dma_free_wc(fbi
->dev
, info
->fix
.smem_len
,
795 info
->screen_base
, info
->fix
.smem_start
);
797 clk_disable_unprepare(fbi
->clk
);
799 framebuffer_release(info
);
804 static struct platform_driver pxa168fb_driver
= {
808 .probe
= pxa168fb_probe
,
809 .remove
= pxa168fb_remove
,
812 module_platform_driver(pxa168fb_driver
);
814 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
815 "Green Wan <gwan@marvell.com>");
816 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
817 MODULE_LICENSE("GPL");