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>
24 #include <linux/ioport.h>
25 #include <linux/platform_device.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/clk.h>
28 #include <linux/err.h>
29 #include <linux/uaccess.h>
30 #include <video/pxa168fb.h>
34 #define DEFAULT_REFRESH 60 /* Hz */
36 static int determine_best_pix_fmt(struct fb_var_screeninfo
*var
)
41 if (var
->bits_per_pixel
== 8)
42 return PIX_FMT_PSEUDOCOLOR
;
47 if (var
->bits_per_pixel
== 16 && var
->red
.length
<= 5 &&
48 var
->green
.length
<= 6 && var
->blue
.length
<= 5) {
49 if (var
->transp
.length
== 0) {
50 if (var
->red
.offset
>= var
->blue
.offset
)
51 return PIX_FMT_RGB565
;
53 return PIX_FMT_BGR565
;
56 if (var
->transp
.length
== 1 && var
->green
.length
<= 5) {
57 if (var
->red
.offset
>= var
->blue
.offset
)
58 return PIX_FMT_RGB1555
;
60 return PIX_FMT_BGR1555
;
69 if (var
->bits_per_pixel
<= 32 && var
->red
.length
<= 8 &&
70 var
->green
.length
<= 8 && var
->blue
.length
<= 8) {
71 if (var
->bits_per_pixel
== 24 && var
->transp
.length
== 0) {
72 if (var
->red
.offset
>= var
->blue
.offset
)
73 return PIX_FMT_RGB888PACK
;
75 return PIX_FMT_BGR888PACK
;
78 if (var
->bits_per_pixel
== 32 && var
->transp
.length
== 8) {
79 if (var
->red
.offset
>= var
->blue
.offset
)
80 return PIX_FMT_RGBA888
;
82 return PIX_FMT_BGRA888
;
84 if (var
->red
.offset
>= var
->blue
.offset
)
85 return PIX_FMT_RGB888UNPACK
;
87 return PIX_FMT_BGR888UNPACK
;
96 static void set_pix_fmt(struct fb_var_screeninfo
*var
, int pix_fmt
)
100 var
->bits_per_pixel
= 16;
101 var
->red
.offset
= 11; var
->red
.length
= 5;
102 var
->green
.offset
= 5; var
->green
.length
= 6;
103 var
->blue
.offset
= 0; var
->blue
.length
= 5;
104 var
->transp
.offset
= 0; var
->transp
.length
= 0;
107 var
->bits_per_pixel
= 16;
108 var
->red
.offset
= 0; var
->red
.length
= 5;
109 var
->green
.offset
= 5; var
->green
.length
= 6;
110 var
->blue
.offset
= 11; var
->blue
.length
= 5;
111 var
->transp
.offset
= 0; var
->transp
.length
= 0;
113 case PIX_FMT_RGB1555
:
114 var
->bits_per_pixel
= 16;
115 var
->red
.offset
= 10; var
->red
.length
= 5;
116 var
->green
.offset
= 5; var
->green
.length
= 5;
117 var
->blue
.offset
= 0; var
->blue
.length
= 5;
118 var
->transp
.offset
= 15; var
->transp
.length
= 1;
120 case PIX_FMT_BGR1555
:
121 var
->bits_per_pixel
= 16;
122 var
->red
.offset
= 0; var
->red
.length
= 5;
123 var
->green
.offset
= 5; var
->green
.length
= 5;
124 var
->blue
.offset
= 10; var
->blue
.length
= 5;
125 var
->transp
.offset
= 15; var
->transp
.length
= 1;
127 case PIX_FMT_RGB888PACK
:
128 var
->bits_per_pixel
= 24;
129 var
->red
.offset
= 16; var
->red
.length
= 8;
130 var
->green
.offset
= 8; var
->green
.length
= 8;
131 var
->blue
.offset
= 0; var
->blue
.length
= 8;
132 var
->transp
.offset
= 0; var
->transp
.length
= 0;
134 case PIX_FMT_BGR888PACK
:
135 var
->bits_per_pixel
= 24;
136 var
->red
.offset
= 0; var
->red
.length
= 8;
137 var
->green
.offset
= 8; var
->green
.length
= 8;
138 var
->blue
.offset
= 16; var
->blue
.length
= 8;
139 var
->transp
.offset
= 0; var
->transp
.length
= 0;
141 case PIX_FMT_RGBA888
:
142 var
->bits_per_pixel
= 32;
143 var
->red
.offset
= 16; var
->red
.length
= 8;
144 var
->green
.offset
= 8; var
->green
.length
= 8;
145 var
->blue
.offset
= 0; var
->blue
.length
= 8;
146 var
->transp
.offset
= 24; var
->transp
.length
= 8;
148 case PIX_FMT_BGRA888
:
149 var
->bits_per_pixel
= 32;
150 var
->red
.offset
= 0; var
->red
.length
= 8;
151 var
->green
.offset
= 8; var
->green
.length
= 8;
152 var
->blue
.offset
= 16; var
->blue
.length
= 8;
153 var
->transp
.offset
= 24; var
->transp
.length
= 8;
155 case PIX_FMT_PSEUDOCOLOR
:
156 var
->bits_per_pixel
= 8;
157 var
->red
.offset
= 0; var
->red
.length
= 8;
158 var
->green
.offset
= 0; var
->green
.length
= 8;
159 var
->blue
.offset
= 0; var
->blue
.length
= 8;
160 var
->transp
.offset
= 0; var
->transp
.length
= 0;
165 static void set_mode(struct pxa168fb_info
*fbi
, struct fb_var_screeninfo
*var
,
166 struct fb_videomode
*mode
, int pix_fmt
, int ystretch
)
168 struct fb_info
*info
= fbi
->info
;
170 set_pix_fmt(var
, pix_fmt
);
172 var
->xres
= mode
->xres
;
173 var
->yres
= mode
->yres
;
174 var
->xres_virtual
= max(var
->xres
, var
->xres_virtual
);
176 var
->yres_virtual
= info
->fix
.smem_len
/
177 (var
->xres_virtual
* (var
->bits_per_pixel
>> 3));
179 var
->yres_virtual
= max(var
->yres
, var
->yres_virtual
);
181 var
->accel_flags
= FB_ACCEL_NONE
;
182 var
->pixclock
= mode
->pixclock
;
183 var
->left_margin
= mode
->left_margin
;
184 var
->right_margin
= mode
->right_margin
;
185 var
->upper_margin
= mode
->upper_margin
;
186 var
->lower_margin
= mode
->lower_margin
;
187 var
->hsync_len
= mode
->hsync_len
;
188 var
->vsync_len
= mode
->vsync_len
;
189 var
->sync
= mode
->sync
;
190 var
->vmode
= FB_VMODE_NONINTERLACED
;
191 var
->rotate
= FB_ROTATE_UR
;
194 static int pxa168fb_check_var(struct fb_var_screeninfo
*var
,
195 struct fb_info
*info
)
197 struct pxa168fb_info
*fbi
= info
->par
;
201 * Determine which pixel format we're going to use.
203 pix_fmt
= determine_best_pix_fmt(var
);
206 set_pix_fmt(var
, pix_fmt
);
207 fbi
->pix_fmt
= pix_fmt
;
210 * Basic geometry sanity checks.
212 if (var
->xoffset
+ var
->xres
> var
->xres_virtual
)
214 if (var
->yoffset
+ var
->yres
> var
->yres_virtual
)
216 if (var
->xres
+ var
->right_margin
+
217 var
->hsync_len
+ var
->left_margin
> 2048)
219 if (var
->yres
+ var
->lower_margin
+
220 var
->vsync_len
+ var
->upper_margin
> 2048)
224 * Check size of framebuffer.
226 if (var
->xres_virtual
* var
->yres_virtual
*
227 (var
->bits_per_pixel
>> 3) > info
->fix
.smem_len
)
234 * The hardware clock divider has an integer and a fractional
237 * clk2 = clk_in / integer_divider
238 * clk_out = clk2 * (1 - (fractional_divider >> 12))
240 * Calculate integer and fractional divider for given clk_in
243 static void set_clock_divider(struct pxa168fb_info
*fbi
,
244 const struct fb_videomode
*m
)
252 * Notice: The field pixclock is used by linux fb
253 * is in pixel second. E.g. struct fb_videomode &
254 * struct fb_var_screeninfo
258 * Check input values.
260 if (!m
|| !m
->pixclock
|| !m
->refresh
) {
261 dev_err(fbi
->dev
, "Input refresh or pixclock is wrong.\n");
266 * Using PLL/AXI clock.
271 * Calc divider according to refresh rate.
273 div_result
= 1000000000000ll;
274 do_div(div_result
, m
->pixclock
);
275 needed_pixclk
= (u32
)div_result
;
277 divider_int
= clk_get_rate(fbi
->clk
) / needed_pixclk
;
279 /* check whether divisor is too small. */
280 if (divider_int
< 2) {
281 dev_warn(fbi
->dev
, "Warning: clock source is too slow."
282 "Try smaller resolution\n");
287 * Set setting to reg.
290 writel(x
, fbi
->reg_base
+ LCD_CFG_SCLK_DIV
);
293 static void set_dma_control0(struct pxa168fb_info
*fbi
)
298 * Set bit to enable graphics DMA.
300 x
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
301 x
&= ~CFG_GRA_ENA_MASK
;
302 x
|= fbi
->active
? CFG_GRA_ENA(1) : CFG_GRA_ENA(0);
305 * If we are in a pseudo-color mode, we need to enable
308 if (fbi
->pix_fmt
== PIX_FMT_PSEUDOCOLOR
)
312 * Configure hardware pixel format.
315 x
|= (fbi
->pix_fmt
>> 1) << 16;
318 * Check red and blue pixel swap.
319 * 1. source data swap
320 * 2. panel output data swap
323 x
|= ((fbi
->pix_fmt
& 1) ^ (fbi
->panel_rbswap
)) << 12;
325 writel(x
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
328 static void set_dma_control1(struct pxa168fb_info
*fbi
, int sync
)
333 * Configure default bits: vsync triggers DMA, gated clock
334 * enable, power save enable, configure alpha registers to
335 * display 100% graphics, and set pixel command.
337 x
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL1
);
341 * We trigger DMA on the falling edge of vsync if vsync is
342 * active low, or on the rising edge if vsync is active high.
344 if (!(sync
& FB_SYNC_VERT_HIGH_ACT
))
347 writel(x
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL1
);
350 static void set_graphics_start(struct fb_info
*info
, int xoffset
, int yoffset
)
352 struct pxa168fb_info
*fbi
= info
->par
;
353 struct fb_var_screeninfo
*var
= &info
->var
;
357 pixel_offset
= (yoffset
* var
->xres_virtual
) + xoffset
;
359 addr
= fbi
->fb_start_dma
+ (pixel_offset
* (var
->bits_per_pixel
>> 3));
360 writel(addr
, fbi
->reg_base
+ LCD_CFG_GRA_START_ADDR0
);
363 static void set_dumb_panel_control(struct fb_info
*info
)
365 struct pxa168fb_info
*fbi
= info
->par
;
366 struct pxa168fb_mach_info
*mi
= fbi
->dev
->platform_data
;
370 * Preserve enable flag.
372 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
) & 0x00000001;
374 x
|= (fbi
->is_blanked
? 0x7 : mi
->dumb_mode
) << 28;
375 x
|= mi
->gpio_output_data
<< 20;
376 x
|= mi
->gpio_output_mask
<< 12;
377 x
|= mi
->panel_rgb_reverse_lanes
? 0x00000080 : 0;
378 x
|= mi
->invert_composite_blank
? 0x00000040 : 0;
379 x
|= (info
->var
.sync
& FB_SYNC_COMP_HIGH_ACT
) ? 0x00000020 : 0;
380 x
|= mi
->invert_pix_val_ena
? 0x00000010 : 0;
381 x
|= (info
->var
.sync
& FB_SYNC_VERT_HIGH_ACT
) ? 0 : 0x00000008;
382 x
|= (info
->var
.sync
& FB_SYNC_HOR_HIGH_ACT
) ? 0 : 0x00000004;
383 x
|= mi
->invert_pixclock
? 0x00000002 : 0;
385 writel(x
, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
388 static void set_dumb_screen_dimensions(struct fb_info
*info
)
390 struct pxa168fb_info
*fbi
= info
->par
;
391 struct fb_var_screeninfo
*v
= &info
->var
;
395 x
= v
->xres
+ v
->right_margin
+ v
->hsync_len
+ v
->left_margin
;
396 y
= v
->yres
+ v
->lower_margin
+ v
->vsync_len
+ v
->upper_margin
;
398 writel((y
<< 16) | x
, fbi
->reg_base
+ LCD_SPUT_V_H_TOTAL
);
401 static int pxa168fb_set_par(struct fb_info
*info
)
403 struct pxa168fb_info
*fbi
= info
->par
;
404 struct fb_var_screeninfo
*var
= &info
->var
;
405 struct fb_videomode mode
;
407 struct pxa168fb_mach_info
*mi
;
409 mi
= fbi
->dev
->platform_data
;
412 * Set additional mode info.
414 if (fbi
->pix_fmt
== PIX_FMT_PSEUDOCOLOR
)
415 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
417 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
418 info
->fix
.line_length
= var
->xres_virtual
* var
->bits_per_pixel
/ 8;
419 info
->fix
.ypanstep
= var
->yres
;
422 * Disable panel output while we setup the display.
424 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
425 writel(x
& ~1, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
428 * Configure global panel parameters.
430 writel((var
->yres
<< 16) | var
->xres
,
431 fbi
->reg_base
+ LCD_SPU_V_H_ACTIVE
);
434 * convet var to video mode
436 fb_var_to_videomode(&mode
, &info
->var
);
438 /* Calculate clock divisor. */
439 set_clock_divider(fbi
, &mode
);
441 /* Configure dma ctrl regs. */
442 set_dma_control0(fbi
);
443 set_dma_control1(fbi
, info
->var
.sync
);
446 * Configure graphics DMA parameters.
448 x
= readl(fbi
->reg_base
+ LCD_CFG_GRA_PITCH
);
449 x
= (x
& ~0xFFFF) | ((var
->xres_virtual
* var
->bits_per_pixel
) >> 3);
450 writel(x
, fbi
->reg_base
+ LCD_CFG_GRA_PITCH
);
451 writel((var
->yres
<< 16) | var
->xres
,
452 fbi
->reg_base
+ LCD_SPU_GRA_HPXL_VLN
);
453 writel((var
->yres
<< 16) | var
->xres
,
454 fbi
->reg_base
+ LCD_SPU_GZM_HPXL_VLN
);
457 * Configure dumb panel ctrl regs & timings.
459 set_dumb_panel_control(info
);
460 set_dumb_screen_dimensions(info
);
462 writel((var
->left_margin
<< 16) | var
->right_margin
,
463 fbi
->reg_base
+ LCD_SPU_H_PORCH
);
464 writel((var
->upper_margin
<< 16) | var
->lower_margin
,
465 fbi
->reg_base
+ LCD_SPU_V_PORCH
);
468 * Re-enable panel output.
470 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
471 writel(x
| 1, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
476 static unsigned int chan_to_field(unsigned int chan
, struct fb_bitfield
*bf
)
478 return ((chan
& 0xffff) >> (16 - bf
->length
)) << bf
->offset
;
481 static u32
to_rgb(u16 red
, u16 green
, u16 blue
)
487 return (red
<< 16) | (green
<< 8) | blue
;
491 pxa168fb_setcolreg(unsigned int regno
, unsigned int red
, unsigned int green
,
492 unsigned int blue
, unsigned int trans
, struct fb_info
*info
)
494 struct pxa168fb_info
*fbi
= info
->par
;
497 if (info
->var
.grayscale
)
498 red
= green
= blue
= (19595 * red
+ 38470 * green
+
501 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
&& regno
< 16) {
502 val
= chan_to_field(red
, &info
->var
.red
);
503 val
|= chan_to_field(green
, &info
->var
.green
);
504 val
|= chan_to_field(blue
, &info
->var
.blue
);
505 fbi
->pseudo_palette
[regno
] = val
;
508 if (info
->fix
.visual
== FB_VISUAL_PSEUDOCOLOR
&& regno
< 256) {
509 val
= to_rgb(red
, green
, blue
);
510 writel(val
, fbi
->reg_base
+ LCD_SPU_SRAM_WRDAT
);
511 writel(0x8300 | regno
, fbi
->reg_base
+ LCD_SPU_SRAM_CTRL
);
517 static int pxa168fb_blank(int blank
, struct fb_info
*info
)
519 struct pxa168fb_info
*fbi
= info
->par
;
521 fbi
->is_blanked
= (blank
== FB_BLANK_UNBLANK
) ? 0 : 1;
522 set_dumb_panel_control(info
);
527 static int pxa168fb_pan_display(struct fb_var_screeninfo
*var
,
528 struct fb_info
*info
)
530 set_graphics_start(info
, var
->xoffset
, var
->yoffset
);
535 static irqreturn_t
pxa168fb_handle_irq(int irq
, void *dev_id
)
537 struct pxa168fb_info
*fbi
= dev_id
;
538 u32 isr
= readl(fbi
->reg_base
+ SPU_IRQ_ISR
);
540 if ((isr
& GRA_FRAME_IRQ0_ENA_MASK
)) {
542 writel(isr
& (~GRA_FRAME_IRQ0_ENA_MASK
),
543 fbi
->reg_base
+ SPU_IRQ_ISR
);
550 static struct fb_ops pxa168fb_ops
= {
551 .owner
= THIS_MODULE
,
552 .fb_check_var
= pxa168fb_check_var
,
553 .fb_set_par
= pxa168fb_set_par
,
554 .fb_setcolreg
= pxa168fb_setcolreg
,
555 .fb_blank
= pxa168fb_blank
,
556 .fb_pan_display
= pxa168fb_pan_display
,
557 .fb_fillrect
= cfb_fillrect
,
558 .fb_copyarea
= cfb_copyarea
,
559 .fb_imageblit
= cfb_imageblit
,
562 static int __devinit
pxa168fb_init_mode(struct fb_info
*info
,
563 struct pxa168fb_mach_info
*mi
)
565 struct pxa168fb_info
*fbi
= info
->par
;
566 struct fb_var_screeninfo
*var
= &info
->var
;
568 u32 total_w
, total_h
, refresh
;
570 const struct fb_videomode
*m
;
575 refresh
= DEFAULT_REFRESH
;
577 /* try to find best video mode. */
578 m
= fb_find_best_mode(&info
->var
, &info
->modelist
);
580 fb_videomode_to_var(&info
->var
, m
);
583 var
->xres_virtual
= var
->xres
;
584 var
->yres_virtual
= info
->fix
.smem_len
/
585 (var
->xres_virtual
* (var
->bits_per_pixel
>> 3));
586 dev_dbg(fbi
->dev
, "pxa168fb: find best mode: res = %dx%d\n",
587 var
->xres
, var
->yres
);
589 /* correct pixclock. */
590 total_w
= var
->xres
+ var
->left_margin
+ var
->right_margin
+
592 total_h
= var
->yres
+ var
->upper_margin
+ var
->lower_margin
+
595 div_result
= 1000000000000ll;
596 do_div(div_result
, total_w
* total_h
* refresh
);
597 var
->pixclock
= (u32
)div_result
;
602 static int __devinit
pxa168fb_probe(struct platform_device
*pdev
)
604 struct pxa168fb_mach_info
*mi
;
605 struct fb_info
*info
= 0;
606 struct pxa168fb_info
*fbi
= 0;
607 struct resource
*res
;
611 mi
= pdev
->dev
.platform_data
;
613 dev_err(&pdev
->dev
, "no platform data defined\n");
617 clk
= clk_get(&pdev
->dev
, "LCDCLK");
619 dev_err(&pdev
->dev
, "unable to get LCDCLK");
623 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
625 dev_err(&pdev
->dev
, "no IO memory defined\n");
630 irq
= platform_get_irq(pdev
, 0);
632 dev_err(&pdev
->dev
, "no IRQ defined\n");
637 info
= framebuffer_alloc(sizeof(struct pxa168fb_info
), &pdev
->dev
);
643 /* Initialize private data */
647 fbi
->dev
= info
->dev
= &pdev
->dev
;
648 fbi
->panel_rbswap
= mi
->panel_rbswap
;
650 fbi
->active
= mi
->active
;
653 * Initialise static fb parameters.
655 info
->flags
= FBINFO_DEFAULT
| FBINFO_PARTIAL_PAN_OK
|
656 FBINFO_HWACCEL_XPAN
| FBINFO_HWACCEL_YPAN
;
658 strlcpy(info
->fix
.id
, mi
->id
, 16);
659 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
660 info
->fix
.type_aux
= 0;
661 info
->fix
.xpanstep
= 0;
662 info
->fix
.ypanstep
= 0;
663 info
->fix
.ywrapstep
= 0;
664 info
->fix
.mmio_start
= res
->start
;
665 info
->fix
.mmio_len
= resource_size(res
);
666 info
->fix
.accel
= FB_ACCEL_NONE
;
667 info
->fbops
= &pxa168fb_ops
;
668 info
->pseudo_palette
= fbi
->pseudo_palette
;
671 * Map LCD controller registers.
673 fbi
->reg_base
= ioremap_nocache(res
->start
, resource_size(res
));
674 if (fbi
->reg_base
== NULL
) {
676 goto failed_free_info
;
680 * Allocate framebuffer memory.
682 info
->fix
.smem_len
= PAGE_ALIGN(DEFAULT_FB_SIZE
);
684 info
->screen_base
= dma_alloc_writecombine(fbi
->dev
, info
->fix
.smem_len
,
685 &fbi
->fb_start_dma
, GFP_KERNEL
);
686 if (info
->screen_base
== NULL
) {
688 goto failed_free_info
;
691 info
->fix
.smem_start
= (unsigned long)fbi
->fb_start_dma
;
692 set_graphics_start(info
, 0, 0);
695 * Set video mode according to platform data.
697 set_mode(fbi
, &info
->var
, mi
->modes
, mi
->pix_fmt
, 1);
699 fb_videomode_to_modelist(mi
->modes
, mi
->num_modes
, &info
->modelist
);
702 * init video mode data.
704 pxa168fb_init_mode(info
, mi
);
707 * Fill in sane defaults.
709 ret
= pxa168fb_check_var(&info
->var
, info
);
711 goto failed_free_fbmem
;
714 * enable controller clock
716 clk_enable(fbi
->clk
);
718 pxa168fb_set_par(info
);
721 * Configure default register values.
723 writel(0, fbi
->reg_base
+ LCD_SPU_BLANKCOLOR
);
724 writel(mi
->io_pin_allocation_mode
, fbi
->reg_base
+ SPU_IOPAD_CONTROL
);
725 writel(0, fbi
->reg_base
+ LCD_CFG_GRA_START_ADDR1
);
726 writel(0, fbi
->reg_base
+ LCD_SPU_GRA_OVSA_HPXL_VLN
);
727 writel(0, fbi
->reg_base
+ LCD_SPU_SRAM_PARA0
);
728 writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
729 fbi
->reg_base
+ LCD_SPU_SRAM_PARA1
);
732 * Allocate color map.
734 if (fb_alloc_cmap(&info
->cmap
, 256, 0) < 0) {
736 goto failed_free_clk
;
740 * Register irq handler.
742 ret
= request_irq(irq
, pxa168fb_handle_irq
, IRQF_SHARED
,
745 dev_err(&pdev
->dev
, "unable to request IRQ\n");
747 goto failed_free_cmap
;
751 * Enable GFX interrupt
753 writel(GRA_FRAME_IRQ0_ENA(0x1), fbi
->reg_base
+ SPU_IRQ_ENA
);
756 * Register framebuffer.
758 ret
= register_framebuffer(info
);
760 dev_err(&pdev
->dev
, "Failed to register pxa168-fb: %d\n", ret
);
762 goto failed_free_irq
;
765 platform_set_drvdata(pdev
, fbi
);
771 fb_dealloc_cmap(&info
->cmap
);
773 clk_disable(fbi
->clk
);
775 dma_free_coherent(fbi
->dev
, info
->fix
.smem_len
,
776 info
->screen_base
, fbi
->fb_start_dma
);
782 dev_err(&pdev
->dev
, "frame buffer device init failed with %d\n", ret
);
786 static int __devexit
pxa168fb_remove(struct platform_device
*pdev
)
788 struct pxa168fb_info
*fbi
= platform_get_drvdata(pdev
);
789 struct fb_info
*info
;
796 /* disable DMA transfer */
797 data
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
798 data
&= ~CFG_GRA_ENA_MASK
;
799 writel(data
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
803 unregister_framebuffer(info
);
805 writel(GRA_FRAME_IRQ0_ENA(0x0), fbi
->reg_base
+ SPU_IRQ_ENA
);
808 fb_dealloc_cmap(&info
->cmap
);
810 irq
= platform_get_irq(pdev
, 0);
813 dma_free_writecombine(fbi
->dev
, PAGE_ALIGN(info
->fix
.smem_len
),
814 info
->screen_base
, info
->fix
.smem_start
);
816 iounmap(fbi
->reg_base
);
818 clk_disable(fbi
->clk
);
821 framebuffer_release(info
);
826 static struct platform_driver pxa168fb_driver
= {
829 .owner
= THIS_MODULE
,
831 .probe
= pxa168fb_probe
,
832 .remove
= __devexit_p(pxa168fb_remove
),
835 module_platform_driver(pxa168fb_driver
);
837 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
838 "Green Wan <gwan@marvell.com>");
839 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
840 MODULE_LICENSE("GPL");