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
;
70 if (var
->bits_per_pixel
<= 32 && var
->red
.length
<= 8 &&
71 var
->green
.length
<= 8 && var
->blue
.length
<= 8) {
72 if (var
->bits_per_pixel
== 24 && var
->transp
.length
== 0) {
73 if (var
->red
.offset
>= var
->blue
.offset
)
74 return PIX_FMT_RGB888PACK
;
76 return PIX_FMT_BGR888PACK
;
79 if (var
->bits_per_pixel
== 32 && var
->transp
.length
== 8) {
80 if (var
->red
.offset
>= var
->blue
.offset
)
81 return PIX_FMT_RGBA888
;
83 return PIX_FMT_BGRA888
;
85 if (var
->red
.offset
>= var
->blue
.offset
)
86 return PIX_FMT_RGB888UNPACK
;
88 return PIX_FMT_BGR888UNPACK
;
97 static void set_pix_fmt(struct fb_var_screeninfo
*var
, int pix_fmt
)
101 var
->bits_per_pixel
= 16;
102 var
->red
.offset
= 11; var
->red
.length
= 5;
103 var
->green
.offset
= 5; var
->green
.length
= 6;
104 var
->blue
.offset
= 0; var
->blue
.length
= 5;
105 var
->transp
.offset
= 0; var
->transp
.length
= 0;
108 var
->bits_per_pixel
= 16;
109 var
->red
.offset
= 0; var
->red
.length
= 5;
110 var
->green
.offset
= 5; var
->green
.length
= 6;
111 var
->blue
.offset
= 11; var
->blue
.length
= 5;
112 var
->transp
.offset
= 0; var
->transp
.length
= 0;
114 case PIX_FMT_RGB1555
:
115 var
->bits_per_pixel
= 16;
116 var
->red
.offset
= 10; var
->red
.length
= 5;
117 var
->green
.offset
= 5; var
->green
.length
= 5;
118 var
->blue
.offset
= 0; var
->blue
.length
= 5;
119 var
->transp
.offset
= 15; var
->transp
.length
= 1;
121 case PIX_FMT_BGR1555
:
122 var
->bits_per_pixel
= 16;
123 var
->red
.offset
= 0; var
->red
.length
= 5;
124 var
->green
.offset
= 5; var
->green
.length
= 5;
125 var
->blue
.offset
= 10; var
->blue
.length
= 5;
126 var
->transp
.offset
= 15; var
->transp
.length
= 1;
128 case PIX_FMT_RGB888PACK
:
129 var
->bits_per_pixel
= 24;
130 var
->red
.offset
= 16; var
->red
.length
= 8;
131 var
->green
.offset
= 8; var
->green
.length
= 8;
132 var
->blue
.offset
= 0; var
->blue
.length
= 8;
133 var
->transp
.offset
= 0; var
->transp
.length
= 0;
135 case PIX_FMT_BGR888PACK
:
136 var
->bits_per_pixel
= 24;
137 var
->red
.offset
= 0; var
->red
.length
= 8;
138 var
->green
.offset
= 8; var
->green
.length
= 8;
139 var
->blue
.offset
= 16; var
->blue
.length
= 8;
140 var
->transp
.offset
= 0; var
->transp
.length
= 0;
142 case PIX_FMT_RGBA888
:
143 var
->bits_per_pixel
= 32;
144 var
->red
.offset
= 16; var
->red
.length
= 8;
145 var
->green
.offset
= 8; var
->green
.length
= 8;
146 var
->blue
.offset
= 0; var
->blue
.length
= 8;
147 var
->transp
.offset
= 24; var
->transp
.length
= 8;
149 case PIX_FMT_BGRA888
:
150 var
->bits_per_pixel
= 32;
151 var
->red
.offset
= 0; var
->red
.length
= 8;
152 var
->green
.offset
= 8; var
->green
.length
= 8;
153 var
->blue
.offset
= 16; var
->blue
.length
= 8;
154 var
->transp
.offset
= 24; var
->transp
.length
= 8;
156 case PIX_FMT_PSEUDOCOLOR
:
157 var
->bits_per_pixel
= 8;
158 var
->red
.offset
= 0; var
->red
.length
= 8;
159 var
->green
.offset
= 0; var
->green
.length
= 8;
160 var
->blue
.offset
= 0; var
->blue
.length
= 8;
161 var
->transp
.offset
= 0; var
->transp
.length
= 0;
166 static void set_mode(struct pxa168fb_info
*fbi
, struct fb_var_screeninfo
*var
,
167 struct fb_videomode
*mode
, int pix_fmt
, int ystretch
)
169 struct fb_info
*info
= fbi
->info
;
171 set_pix_fmt(var
, pix_fmt
);
173 var
->xres
= mode
->xres
;
174 var
->yres
= mode
->yres
;
175 var
->xres_virtual
= max(var
->xres
, var
->xres_virtual
);
177 var
->yres_virtual
= info
->fix
.smem_len
/
178 (var
->xres_virtual
* (var
->bits_per_pixel
>> 3));
180 var
->yres_virtual
= max(var
->yres
, var
->yres_virtual
);
182 var
->accel_flags
= FB_ACCEL_NONE
;
183 var
->pixclock
= mode
->pixclock
;
184 var
->left_margin
= mode
->left_margin
;
185 var
->right_margin
= mode
->right_margin
;
186 var
->upper_margin
= mode
->upper_margin
;
187 var
->lower_margin
= mode
->lower_margin
;
188 var
->hsync_len
= mode
->hsync_len
;
189 var
->vsync_len
= mode
->vsync_len
;
190 var
->sync
= mode
->sync
;
191 var
->vmode
= FB_VMODE_NONINTERLACED
;
192 var
->rotate
= FB_ROTATE_UR
;
195 static int pxa168fb_check_var(struct fb_var_screeninfo
*var
,
196 struct fb_info
*info
)
198 struct pxa168fb_info
*fbi
= info
->par
;
202 * Determine which pixel format we're going to use.
204 pix_fmt
= determine_best_pix_fmt(var
);
207 set_pix_fmt(var
, pix_fmt
);
208 fbi
->pix_fmt
= pix_fmt
;
211 * Basic geometry sanity checks.
213 if (var
->xoffset
+ var
->xres
> var
->xres_virtual
)
215 if (var
->yoffset
+ var
->yres
> var
->yres_virtual
)
217 if (var
->xres
+ var
->right_margin
+
218 var
->hsync_len
+ var
->left_margin
> 2048)
220 if (var
->yres
+ var
->lower_margin
+
221 var
->vsync_len
+ var
->upper_margin
> 2048)
225 * Check size of framebuffer.
227 if (var
->xres_virtual
* var
->yres_virtual
*
228 (var
->bits_per_pixel
>> 3) > info
->fix
.smem_len
)
235 * The hardware clock divider has an integer and a fractional
238 * clk2 = clk_in / integer_divider
239 * clk_out = clk2 * (1 - (fractional_divider >> 12))
241 * Calculate integer and fractional divider for given clk_in
244 static void set_clock_divider(struct pxa168fb_info
*fbi
,
245 const struct fb_videomode
*m
)
253 * Notice: The field pixclock is used by linux fb
254 * is in pixel second. E.g. struct fb_videomode &
255 * struct fb_var_screeninfo
259 * Check input values.
261 if (!m
|| !m
->pixclock
|| !m
->refresh
) {
262 dev_err(fbi
->dev
, "Input refresh or pixclock is wrong.\n");
267 * Using PLL/AXI clock.
272 * Calc divider according to refresh rate.
274 div_result
= 1000000000000ll;
275 do_div(div_result
, m
->pixclock
);
276 needed_pixclk
= (u32
)div_result
;
278 divider_int
= clk_get_rate(fbi
->clk
) / needed_pixclk
;
280 /* check whether divisor is too small. */
281 if (divider_int
< 2) {
282 dev_warn(fbi
->dev
, "Warning: clock source is too slow."
283 "Try smaller resolution\n");
288 * Set setting to reg.
291 writel(x
, fbi
->reg_base
+ LCD_CFG_SCLK_DIV
);
294 static void set_dma_control0(struct pxa168fb_info
*fbi
)
299 * Set bit to enable graphics DMA.
301 x
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
302 x
&= ~CFG_GRA_ENA_MASK
;
303 x
|= fbi
->active
? CFG_GRA_ENA(1) : CFG_GRA_ENA(0);
306 * If we are in a pseudo-color mode, we need to enable
309 if (fbi
->pix_fmt
== PIX_FMT_PSEUDOCOLOR
)
313 * Configure hardware pixel format.
316 x
|= (fbi
->pix_fmt
>> 1) << 16;
319 * Check red and blue pixel swap.
320 * 1. source data swap
321 * 2. panel output data swap
324 x
|= ((fbi
->pix_fmt
& 1) ^ (fbi
->panel_rbswap
)) << 12;
326 writel(x
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
329 static void set_dma_control1(struct pxa168fb_info
*fbi
, int sync
)
334 * Configure default bits: vsync triggers DMA, gated clock
335 * enable, power save enable, configure alpha registers to
336 * display 100% graphics, and set pixel command.
338 x
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL1
);
342 * We trigger DMA on the falling edge of vsync if vsync is
343 * active low, or on the rising edge if vsync is active high.
345 if (!(sync
& FB_SYNC_VERT_HIGH_ACT
))
348 writel(x
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL1
);
351 static void set_graphics_start(struct fb_info
*info
, int xoffset
, int yoffset
)
353 struct pxa168fb_info
*fbi
= info
->par
;
354 struct fb_var_screeninfo
*var
= &info
->var
;
358 pixel_offset
= (yoffset
* var
->xres_virtual
) + xoffset
;
360 addr
= fbi
->fb_start_dma
+ (pixel_offset
* (var
->bits_per_pixel
>> 3));
361 writel(addr
, fbi
->reg_base
+ LCD_CFG_GRA_START_ADDR0
);
364 static void set_dumb_panel_control(struct fb_info
*info
)
366 struct pxa168fb_info
*fbi
= info
->par
;
367 struct pxa168fb_mach_info
*mi
= dev_get_platdata(fbi
->dev
);
371 * Preserve enable flag.
373 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
) & 0x00000001;
375 x
|= (fbi
->is_blanked
? 0x7 : mi
->dumb_mode
) << 28;
376 x
|= mi
->gpio_output_data
<< 20;
377 x
|= mi
->gpio_output_mask
<< 12;
378 x
|= mi
->panel_rgb_reverse_lanes
? 0x00000080 : 0;
379 x
|= mi
->invert_composite_blank
? 0x00000040 : 0;
380 x
|= (info
->var
.sync
& FB_SYNC_COMP_HIGH_ACT
) ? 0x00000020 : 0;
381 x
|= mi
->invert_pix_val_ena
? 0x00000010 : 0;
382 x
|= (info
->var
.sync
& FB_SYNC_VERT_HIGH_ACT
) ? 0 : 0x00000008;
383 x
|= (info
->var
.sync
& FB_SYNC_HOR_HIGH_ACT
) ? 0 : 0x00000004;
384 x
|= mi
->invert_pixclock
? 0x00000002 : 0;
386 writel(x
, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
389 static void set_dumb_screen_dimensions(struct fb_info
*info
)
391 struct pxa168fb_info
*fbi
= info
->par
;
392 struct fb_var_screeninfo
*v
= &info
->var
;
396 x
= v
->xres
+ v
->right_margin
+ v
->hsync_len
+ v
->left_margin
;
397 y
= v
->yres
+ v
->lower_margin
+ v
->vsync_len
+ v
->upper_margin
;
399 writel((y
<< 16) | x
, fbi
->reg_base
+ LCD_SPUT_V_H_TOTAL
);
402 static int pxa168fb_set_par(struct fb_info
*info
)
404 struct pxa168fb_info
*fbi
= info
->par
;
405 struct fb_var_screeninfo
*var
= &info
->var
;
406 struct fb_videomode mode
;
408 struct pxa168fb_mach_info
*mi
;
410 mi
= dev_get_platdata(fbi
->dev
);
413 * Set additional mode info.
415 if (fbi
->pix_fmt
== PIX_FMT_PSEUDOCOLOR
)
416 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
418 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
419 info
->fix
.line_length
= var
->xres_virtual
* var
->bits_per_pixel
/ 8;
420 info
->fix
.ypanstep
= var
->yres
;
423 * Disable panel output while we setup the display.
425 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
426 writel(x
& ~1, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
429 * Configure global panel parameters.
431 writel((var
->yres
<< 16) | var
->xres
,
432 fbi
->reg_base
+ LCD_SPU_V_H_ACTIVE
);
435 * convet var to video mode
437 fb_var_to_videomode(&mode
, &info
->var
);
439 /* Calculate clock divisor. */
440 set_clock_divider(fbi
, &mode
);
442 /* Configure dma ctrl regs. */
443 set_dma_control0(fbi
);
444 set_dma_control1(fbi
, info
->var
.sync
);
447 * Configure graphics DMA parameters.
449 x
= readl(fbi
->reg_base
+ LCD_CFG_GRA_PITCH
);
450 x
= (x
& ~0xFFFF) | ((var
->xres_virtual
* var
->bits_per_pixel
) >> 3);
451 writel(x
, fbi
->reg_base
+ LCD_CFG_GRA_PITCH
);
452 writel((var
->yres
<< 16) | var
->xres
,
453 fbi
->reg_base
+ LCD_SPU_GRA_HPXL_VLN
);
454 writel((var
->yres
<< 16) | var
->xres
,
455 fbi
->reg_base
+ LCD_SPU_GZM_HPXL_VLN
);
458 * Configure dumb panel ctrl regs & timings.
460 set_dumb_panel_control(info
);
461 set_dumb_screen_dimensions(info
);
463 writel((var
->left_margin
<< 16) | var
->right_margin
,
464 fbi
->reg_base
+ LCD_SPU_H_PORCH
);
465 writel((var
->upper_margin
<< 16) | var
->lower_margin
,
466 fbi
->reg_base
+ LCD_SPU_V_PORCH
);
469 * Re-enable panel output.
471 x
= readl(fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
472 writel(x
| 1, fbi
->reg_base
+ LCD_SPU_DUMB_CTRL
);
477 static unsigned int chan_to_field(unsigned int chan
, struct fb_bitfield
*bf
)
479 return ((chan
& 0xffff) >> (16 - bf
->length
)) << bf
->offset
;
482 static u32
to_rgb(u16 red
, u16 green
, u16 blue
)
488 return (red
<< 16) | (green
<< 8) | blue
;
492 pxa168fb_setcolreg(unsigned int regno
, unsigned int red
, unsigned int green
,
493 unsigned int blue
, unsigned int trans
, struct fb_info
*info
)
495 struct pxa168fb_info
*fbi
= info
->par
;
498 if (info
->var
.grayscale
)
499 red
= green
= blue
= (19595 * red
+ 38470 * green
+
502 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
&& regno
< 16) {
503 val
= chan_to_field(red
, &info
->var
.red
);
504 val
|= chan_to_field(green
, &info
->var
.green
);
505 val
|= chan_to_field(blue
, &info
->var
.blue
);
506 fbi
->pseudo_palette
[regno
] = val
;
509 if (info
->fix
.visual
== FB_VISUAL_PSEUDOCOLOR
&& regno
< 256) {
510 val
= to_rgb(red
, green
, blue
);
511 writel(val
, fbi
->reg_base
+ LCD_SPU_SRAM_WRDAT
);
512 writel(0x8300 | regno
, fbi
->reg_base
+ LCD_SPU_SRAM_CTRL
);
518 static int pxa168fb_blank(int blank
, struct fb_info
*info
)
520 struct pxa168fb_info
*fbi
= info
->par
;
522 fbi
->is_blanked
= (blank
== FB_BLANK_UNBLANK
) ? 0 : 1;
523 set_dumb_panel_control(info
);
528 static int pxa168fb_pan_display(struct fb_var_screeninfo
*var
,
529 struct fb_info
*info
)
531 set_graphics_start(info
, var
->xoffset
, var
->yoffset
);
536 static irqreturn_t
pxa168fb_handle_irq(int irq
, void *dev_id
)
538 struct pxa168fb_info
*fbi
= dev_id
;
539 u32 isr
= readl(fbi
->reg_base
+ SPU_IRQ_ISR
);
541 if ((isr
& GRA_FRAME_IRQ0_ENA_MASK
)) {
543 writel(isr
& (~GRA_FRAME_IRQ0_ENA_MASK
),
544 fbi
->reg_base
+ SPU_IRQ_ISR
);
551 static struct fb_ops pxa168fb_ops
= {
552 .owner
= THIS_MODULE
,
553 .fb_check_var
= pxa168fb_check_var
,
554 .fb_set_par
= pxa168fb_set_par
,
555 .fb_setcolreg
= pxa168fb_setcolreg
,
556 .fb_blank
= pxa168fb_blank
,
557 .fb_pan_display
= pxa168fb_pan_display
,
558 .fb_fillrect
= cfb_fillrect
,
559 .fb_copyarea
= cfb_copyarea
,
560 .fb_imageblit
= cfb_imageblit
,
563 static int pxa168fb_init_mode(struct fb_info
*info
,
564 struct pxa168fb_mach_info
*mi
)
566 struct pxa168fb_info
*fbi
= info
->par
;
567 struct fb_var_screeninfo
*var
= &info
->var
;
569 u32 total_w
, total_h
, refresh
;
571 const struct fb_videomode
*m
;
576 refresh
= DEFAULT_REFRESH
;
578 /* try to find best video mode. */
579 m
= fb_find_best_mode(&info
->var
, &info
->modelist
);
581 fb_videomode_to_var(&info
->var
, m
);
584 var
->xres_virtual
= var
->xres
;
585 var
->yres_virtual
= info
->fix
.smem_len
/
586 (var
->xres_virtual
* (var
->bits_per_pixel
>> 3));
587 dev_dbg(fbi
->dev
, "pxa168fb: find best mode: res = %dx%d\n",
588 var
->xres
, var
->yres
);
590 /* correct pixclock. */
591 total_w
= var
->xres
+ var
->left_margin
+ var
->right_margin
+
593 total_h
= var
->yres
+ var
->upper_margin
+ var
->lower_margin
+
596 div_result
= 1000000000000ll;
597 do_div(div_result
, total_w
* total_h
* refresh
);
598 var
->pixclock
= (u32
)div_result
;
603 static int pxa168fb_probe(struct platform_device
*pdev
)
605 struct pxa168fb_mach_info
*mi
;
606 struct fb_info
*info
= 0;
607 struct pxa168fb_info
*fbi
= 0;
608 struct resource
*res
;
612 mi
= dev_get_platdata(&pdev
->dev
);
614 dev_err(&pdev
->dev
, "no platform data defined\n");
618 clk
= devm_clk_get(&pdev
->dev
, "LCDCLK");
620 dev_err(&pdev
->dev
, "unable to get LCDCLK");
624 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
626 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");
636 info
= framebuffer_alloc(sizeof(struct pxa168fb_info
), &pdev
->dev
);
641 /* Initialize private data */
645 fbi
->dev
= info
->dev
= &pdev
->dev
;
646 fbi
->panel_rbswap
= mi
->panel_rbswap
;
648 fbi
->active
= mi
->active
;
651 * Initialise static fb parameters.
653 info
->flags
= FBINFO_DEFAULT
| FBINFO_PARTIAL_PAN_OK
|
654 FBINFO_HWACCEL_XPAN
| FBINFO_HWACCEL_YPAN
;
656 strlcpy(info
->fix
.id
, mi
->id
, 16);
657 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
658 info
->fix
.type_aux
= 0;
659 info
->fix
.xpanstep
= 0;
660 info
->fix
.ypanstep
= 0;
661 info
->fix
.ywrapstep
= 0;
662 info
->fix
.mmio_start
= res
->start
;
663 info
->fix
.mmio_len
= resource_size(res
);
664 info
->fix
.accel
= FB_ACCEL_NONE
;
665 info
->fbops
= &pxa168fb_ops
;
666 info
->pseudo_palette
= fbi
->pseudo_palette
;
669 * Map LCD controller registers.
671 fbi
->reg_base
= devm_ioremap_nocache(&pdev
->dev
, res
->start
,
673 if (fbi
->reg_base
== NULL
) {
675 goto failed_free_info
;
679 * Allocate framebuffer memory.
681 info
->fix
.smem_len
= PAGE_ALIGN(DEFAULT_FB_SIZE
);
683 info
->screen_base
= dma_alloc_writecombine(fbi
->dev
, info
->fix
.smem_len
,
684 &fbi
->fb_start_dma
, GFP_KERNEL
);
685 if (info
->screen_base
== NULL
) {
687 goto failed_free_info
;
690 info
->fix
.smem_start
= (unsigned long)fbi
->fb_start_dma
;
691 set_graphics_start(info
, 0, 0);
694 * Set video mode according to platform data.
696 set_mode(fbi
, &info
->var
, mi
->modes
, mi
->pix_fmt
, 1);
698 fb_videomode_to_modelist(mi
->modes
, mi
->num_modes
, &info
->modelist
);
701 * init video mode data.
703 pxa168fb_init_mode(info
, mi
);
706 * Fill in sane defaults.
708 ret
= pxa168fb_check_var(&info
->var
, info
);
710 goto failed_free_fbmem
;
713 * enable controller clock
715 clk_enable(fbi
->clk
);
717 pxa168fb_set_par(info
);
720 * Configure default register values.
722 writel(0, fbi
->reg_base
+ LCD_SPU_BLANKCOLOR
);
723 writel(mi
->io_pin_allocation_mode
, fbi
->reg_base
+ SPU_IOPAD_CONTROL
);
724 writel(0, fbi
->reg_base
+ LCD_CFG_GRA_START_ADDR1
);
725 writel(0, fbi
->reg_base
+ LCD_SPU_GRA_OVSA_HPXL_VLN
);
726 writel(0, fbi
->reg_base
+ LCD_SPU_SRAM_PARA0
);
727 writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
728 fbi
->reg_base
+ LCD_SPU_SRAM_PARA1
);
731 * Allocate color map.
733 if (fb_alloc_cmap(&info
->cmap
, 256, 0) < 0) {
735 goto failed_free_clk
;
739 * Register irq handler.
741 ret
= devm_request_irq(&pdev
->dev
, irq
, pxa168fb_handle_irq
,
742 IRQF_SHARED
, info
->fix
.id
, fbi
);
744 dev_err(&pdev
->dev
, "unable to request IRQ\n");
746 goto failed_free_cmap
;
750 * Enable GFX interrupt
752 writel(GRA_FRAME_IRQ0_ENA(0x1), fbi
->reg_base
+ SPU_IRQ_ENA
);
755 * Register framebuffer.
757 ret
= register_framebuffer(info
);
759 dev_err(&pdev
->dev
, "Failed to register pxa168-fb: %d\n", ret
);
761 goto failed_free_cmap
;
764 platform_set_drvdata(pdev
, fbi
);
768 fb_dealloc_cmap(&info
->cmap
);
770 clk_disable(fbi
->clk
);
772 dma_free_coherent(fbi
->dev
, info
->fix
.smem_len
,
773 info
->screen_base
, fbi
->fb_start_dma
);
777 dev_err(&pdev
->dev
, "frame buffer device init failed with %d\n", ret
);
781 static int pxa168fb_remove(struct platform_device
*pdev
)
783 struct pxa168fb_info
*fbi
= platform_get_drvdata(pdev
);
784 struct fb_info
*info
;
791 /* disable DMA transfer */
792 data
= readl(fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
793 data
&= ~CFG_GRA_ENA_MASK
;
794 writel(data
, fbi
->reg_base
+ LCD_SPU_DMA_CTRL0
);
798 unregister_framebuffer(info
);
800 writel(GRA_FRAME_IRQ0_ENA(0x0), fbi
->reg_base
+ SPU_IRQ_ENA
);
803 fb_dealloc_cmap(&info
->cmap
);
805 irq
= platform_get_irq(pdev
, 0);
807 dma_free_writecombine(fbi
->dev
, PAGE_ALIGN(info
->fix
.smem_len
),
808 info
->screen_base
, info
->fix
.smem_start
);
810 clk_disable(fbi
->clk
);
812 framebuffer_release(info
);
817 static struct platform_driver pxa168fb_driver
= {
821 .probe
= pxa168fb_probe
,
822 .remove
= pxa168fb_remove
,
825 module_platform_driver(pxa168fb_driver
);
827 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
828 "Green Wan <gwan@marvell.com>");
829 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
830 MODULE_LICENSE("GPL");