Merge tag 'mmc-v4.3' of git://git.linaro.org/people/ulf.hansson/mmc
[muen/linux.git] / drivers / video / fbdev / pxa168fb.c
1 /*
2  * linux/drivers/video/pxa168fb.c -- Marvell PXA168 LCD Controller
3  *
4  *  Copyright (C) 2008 Marvell International Ltd.
5  *  All rights reserved.
6  *
7  *  2009-02-16  adapted from original version for PXA168/910
8  *              Jun Nie <njun@marvell.com>
9  *
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
12  * more details.
13  */
14
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>
21 #include <linux/fb.h>
22 #include <linux/delay.h>
23 #include <linux/init.h>
24 #include <linux/io.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>
32
33 #include "pxa168fb.h"
34
35 #define DEFAULT_REFRESH         60      /* Hz */
36
37 static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
38 {
39         /*
40          * Pseudocolor mode?
41          */
42         if (var->bits_per_pixel == 8)
43                 return PIX_FMT_PSEUDOCOLOR;
44
45         /*
46          * Check for 565/1555.
47          */
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;
53                         else
54                                 return PIX_FMT_BGR565;
55                 }
56
57                 if (var->transp.length == 1 && var->green.length <= 5) {
58                         if (var->red.offset >= var->blue.offset)
59                                 return PIX_FMT_RGB1555;
60                         else
61                                 return PIX_FMT_BGR1555;
62                 }
63
64                 /* fall through */
65         }
66
67         /*
68          * Check for 888/A888.
69          */
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;
75                         else
76                                 return PIX_FMT_BGR888PACK;
77                 }
78
79                 if (var->bits_per_pixel == 32 && var->transp.length == 8) {
80                         if (var->red.offset >= var->blue.offset)
81                                 return PIX_FMT_RGBA888;
82                         else
83                                 return PIX_FMT_BGRA888;
84                 } else {
85                         if (var->red.offset >= var->blue.offset)
86                                 return PIX_FMT_RGB888UNPACK;
87                         else
88                                 return PIX_FMT_BGR888UNPACK;
89                 }
90
91                 /* fall through */
92         }
93
94         return -EINVAL;
95 }
96
97 static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt)
98 {
99         switch (pix_fmt) {
100         case PIX_FMT_RGB565:
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;
106                 break;
107         case PIX_FMT_BGR565:
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;
113                 break;
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;
120                 break;
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;
127                 break;
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;
134                 break;
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;
141                 break;
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;
148                 break;
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;
155                 break;
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;
162                 break;
163         }
164 }
165
166 static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var,
167                      struct fb_videomode *mode, int pix_fmt, int ystretch)
168 {
169         struct fb_info *info = fbi->info;
170
171         set_pix_fmt(var, pix_fmt);
172
173         var->xres = mode->xres;
174         var->yres = mode->yres;
175         var->xres_virtual = max(var->xres, var->xres_virtual);
176         if (ystretch)
177                 var->yres_virtual = info->fix.smem_len /
178                         (var->xres_virtual * (var->bits_per_pixel >> 3));
179         else
180                 var->yres_virtual = max(var->yres, var->yres_virtual);
181         var->grayscale = 0;
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;
193 }
194
195 static int pxa168fb_check_var(struct fb_var_screeninfo *var,
196                               struct fb_info *info)
197 {
198         struct pxa168fb_info *fbi = info->par;
199         int pix_fmt;
200
201         /*
202          * Determine which pixel format we're going to use.
203          */
204         pix_fmt = determine_best_pix_fmt(var);
205         if (pix_fmt < 0)
206                 return pix_fmt;
207         set_pix_fmt(var, pix_fmt);
208         fbi->pix_fmt = pix_fmt;
209
210         /*
211          * Basic geometry sanity checks.
212          */
213         if (var->xoffset + var->xres > var->xres_virtual)
214                 return -EINVAL;
215         if (var->yoffset + var->yres > var->yres_virtual)
216                 return -EINVAL;
217         if (var->xres + var->right_margin +
218             var->hsync_len + var->left_margin > 2048)
219                 return -EINVAL;
220         if (var->yres + var->lower_margin +
221             var->vsync_len + var->upper_margin > 2048)
222                 return -EINVAL;
223
224         /*
225          * Check size of framebuffer.
226          */
227         if (var->xres_virtual * var->yres_virtual *
228             (var->bits_per_pixel >> 3) > info->fix.smem_len)
229                 return -EINVAL;
230
231         return 0;
232 }
233
234 /*
235  * The hardware clock divider has an integer and a fractional
236  * stage:
237  *
238  *      clk2 = clk_in / integer_divider
239  *      clk_out = clk2 * (1 - (fractional_divider >> 12))
240  *
241  * Calculate integer and fractional divider for given clk_in
242  * and clk_out.
243  */
244 static void set_clock_divider(struct pxa168fb_info *fbi,
245                               const struct fb_videomode *m)
246 {
247         int divider_int;
248         int needed_pixclk;
249         u64 div_result;
250         u32 x = 0;
251
252         /*
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
256          */
257
258         /*
259          * Check input values.
260          */
261         if (!m || !m->pixclock || !m->refresh) {
262                 dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n");
263                 return;
264         }
265
266         /*
267          * Using PLL/AXI clock.
268          */
269         x = 0x80000000;
270
271         /*
272          * Calc divider according to refresh rate.
273          */
274         div_result = 1000000000000ll;
275         do_div(div_result, m->pixclock);
276         needed_pixclk = (u32)div_result;
277
278         divider_int = clk_get_rate(fbi->clk) / needed_pixclk;
279
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");
284                 divider_int = 2;
285         }
286
287         /*
288          * Set setting to reg.
289          */
290         x |= divider_int;
291         writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV);
292 }
293
294 static void set_dma_control0(struct pxa168fb_info *fbi)
295 {
296         u32 x;
297
298         /*
299          * Set bit to enable graphics DMA.
300          */
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);
304
305         /*
306          * If we are in a pseudo-color mode, we need to enable
307          * palette lookup.
308          */
309         if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
310                 x |= 0x10000000;
311
312         /*
313          * Configure hardware pixel format.
314          */
315         x &= ~(0xF << 16);
316         x |= (fbi->pix_fmt >> 1) << 16;
317
318         /*
319          * Check red and blue pixel swap.
320          * 1. source data swap
321          * 2. panel output data swap
322          */
323         x &= ~(1 << 12);
324         x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12;
325
326         writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0);
327 }
328
329 static void set_dma_control1(struct pxa168fb_info *fbi, int sync)
330 {
331         u32 x;
332
333         /*
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.
337          */
338         x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1);
339         x |= 0x2032ff81;
340
341         /*
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.
344          */
345         if (!(sync & FB_SYNC_VERT_HIGH_ACT))
346                 x |= 0x08000000;
347
348         writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1);
349 }
350
351 static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset)
352 {
353         struct pxa168fb_info *fbi = info->par;
354         struct fb_var_screeninfo *var = &info->var;
355         int pixel_offset;
356         unsigned long addr;
357
358         pixel_offset = (yoffset * var->xres_virtual) + xoffset;
359
360         addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
361         writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0);
362 }
363
364 static void set_dumb_panel_control(struct fb_info *info)
365 {
366         struct pxa168fb_info *fbi = info->par;
367         struct pxa168fb_mach_info *mi = dev_get_platdata(fbi->dev);
368         u32 x;
369
370         /*
371          * Preserve enable flag.
372          */
373         x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001;
374
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;
385
386         writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL);
387 }
388
389 static void set_dumb_screen_dimensions(struct fb_info *info)
390 {
391         struct pxa168fb_info *fbi = info->par;
392         struct fb_var_screeninfo *v = &info->var;
393         int x;
394         int y;
395
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;
398
399         writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL);
400 }
401
402 static int pxa168fb_set_par(struct fb_info *info)
403 {
404         struct pxa168fb_info *fbi = info->par;
405         struct fb_var_screeninfo *var = &info->var;
406         struct fb_videomode mode;
407         u32 x;
408         struct pxa168fb_mach_info *mi;
409
410         mi = dev_get_platdata(fbi->dev);
411
412         /*
413          * Set additional mode info.
414          */
415         if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
416                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
417         else
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;
421
422         /*
423          * Disable panel output while we setup the display.
424          */
425         x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
426         writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
427
428         /*
429          * Configure global panel parameters.
430          */
431         writel((var->yres << 16) | var->xres,
432                 fbi->reg_base + LCD_SPU_V_H_ACTIVE);
433
434         /*
435          * convet var to video mode
436          */
437         fb_var_to_videomode(&mode, &info->var);
438
439         /* Calculate clock divisor. */
440         set_clock_divider(fbi, &mode);
441
442         /* Configure dma ctrl regs. */
443         set_dma_control0(fbi);
444         set_dma_control1(fbi, info->var.sync);
445
446         /*
447          * Configure graphics DMA parameters.
448          */
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);
456
457         /*
458          * Configure dumb panel ctrl regs & timings.
459          */
460         set_dumb_panel_control(info);
461         set_dumb_screen_dimensions(info);
462
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);
467
468         /*
469          * Re-enable panel output.
470          */
471         x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
472         writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
473
474         return 0;
475 }
476
477 static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
478 {
479         return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
480 }
481
482 static u32 to_rgb(u16 red, u16 green, u16 blue)
483 {
484         red >>= 8;
485         green >>= 8;
486         blue >>= 8;
487
488         return (red << 16) | (green << 8) | blue;
489 }
490
491 static int
492 pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
493                  unsigned int blue, unsigned int trans, struct fb_info *info)
494 {
495         struct pxa168fb_info *fbi = info->par;
496         u32 val;
497
498         if (info->var.grayscale)
499                 red = green = blue = (19595 * red + 38470 * green +
500                                         7471 * blue) >> 16;
501
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;
507         }
508
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);
513         }
514
515         return 0;
516 }
517
518 static int pxa168fb_blank(int blank, struct fb_info *info)
519 {
520         struct pxa168fb_info *fbi = info->par;
521
522         fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1;
523         set_dumb_panel_control(info);
524
525         return 0;
526 }
527
528 static int pxa168fb_pan_display(struct fb_var_screeninfo *var,
529                                 struct fb_info *info)
530 {
531         set_graphics_start(info, var->xoffset, var->yoffset);
532
533         return 0;
534 }
535
536 static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id)
537 {
538         struct pxa168fb_info *fbi = dev_id;
539         u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR);
540
541         if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) {
542
543                 writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK),
544                         fbi->reg_base + SPU_IRQ_ISR);
545
546                 return IRQ_HANDLED;
547         }
548         return IRQ_NONE;
549 }
550
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,
561 };
562
563 static int pxa168fb_init_mode(struct fb_info *info,
564                               struct pxa168fb_mach_info *mi)
565 {
566         struct pxa168fb_info *fbi = info->par;
567         struct fb_var_screeninfo *var = &info->var;
568         int ret = 0;
569         u32 total_w, total_h, refresh;
570         u64 div_result;
571         const struct fb_videomode *m;
572
573         /*
574          * Set default value
575          */
576         refresh = DEFAULT_REFRESH;
577
578         /* try to find best video mode. */
579         m = fb_find_best_mode(&info->var, &info->modelist);
580         if (m)
581                 fb_videomode_to_var(&info->var, m);
582
583         /* Init settings. */
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);
589
590         /* correct pixclock. */
591         total_w = var->xres + var->left_margin + var->right_margin +
592                   var->hsync_len;
593         total_h = var->yres + var->upper_margin + var->lower_margin +
594                   var->vsync_len;
595
596         div_result = 1000000000000ll;
597         do_div(div_result, total_w * total_h * refresh);
598         var->pixclock = (u32)div_result;
599
600         return ret;
601 }
602
603 static int pxa168fb_probe(struct platform_device *pdev)
604 {
605         struct pxa168fb_mach_info *mi;
606         struct fb_info *info = 0;
607         struct pxa168fb_info *fbi = 0;
608         struct resource *res;
609         struct clk *clk;
610         int irq, ret;
611
612         mi = dev_get_platdata(&pdev->dev);
613         if (mi == NULL) {
614                 dev_err(&pdev->dev, "no platform data defined\n");
615                 return -EINVAL;
616         }
617
618         clk = clk_get(&pdev->dev, "LCDCLK");
619         if (IS_ERR(clk)) {
620                 dev_err(&pdev->dev, "unable to get LCDCLK");
621                 return PTR_ERR(clk);
622         }
623
624         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
625         if (res == NULL) {
626                 dev_err(&pdev->dev, "no IO memory defined\n");
627                 ret = -ENOENT;
628                 goto failed_put_clk;
629         }
630
631         irq = platform_get_irq(pdev, 0);
632         if (irq < 0) {
633                 dev_err(&pdev->dev, "no IRQ defined\n");
634                 ret = -ENOENT;
635                 goto failed_put_clk;
636         }
637
638         info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
639         if (info == NULL) {
640                 ret = -ENOMEM;
641                 goto failed_put_clk;
642         }
643
644         /* Initialize private data */
645         fbi = info->par;
646         fbi->info = info;
647         fbi->clk = clk;
648         fbi->dev = info->dev = &pdev->dev;
649         fbi->panel_rbswap = mi->panel_rbswap;
650         fbi->is_blanked = 0;
651         fbi->active = mi->active;
652
653         /*
654          * Initialise static fb parameters.
655          */
656         info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
657                       FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
658         info->node = -1;
659         strlcpy(info->fix.id, mi->id, 16);
660         info->fix.type = FB_TYPE_PACKED_PIXELS;
661         info->fix.type_aux = 0;
662         info->fix.xpanstep = 0;
663         info->fix.ypanstep = 0;
664         info->fix.ywrapstep = 0;
665         info->fix.mmio_start = res->start;
666         info->fix.mmio_len = resource_size(res);
667         info->fix.accel = FB_ACCEL_NONE;
668         info->fbops = &pxa168fb_ops;
669         info->pseudo_palette = fbi->pseudo_palette;
670
671         /*
672          * Map LCD controller registers.
673          */
674         fbi->reg_base = devm_ioremap_nocache(&pdev->dev, res->start,
675                                              resource_size(res));
676         if (fbi->reg_base == NULL) {
677                 ret = -ENOMEM;
678                 goto failed_free_info;
679         }
680
681         /*
682          * Allocate framebuffer memory.
683          */
684         info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
685
686         info->screen_base = dma_alloc_writecombine(fbi->dev, info->fix.smem_len,
687                                                 &fbi->fb_start_dma, GFP_KERNEL);
688         if (info->screen_base == NULL) {
689                 ret = -ENOMEM;
690                 goto failed_free_info;
691         }
692
693         info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
694         set_graphics_start(info, 0, 0);
695
696         /*
697          * Set video mode according to platform data.
698          */
699         set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1);
700
701         fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist);
702
703         /*
704          * init video mode data.
705          */
706         pxa168fb_init_mode(info, mi);
707
708         /*
709          * Fill in sane defaults.
710          */
711         ret = pxa168fb_check_var(&info->var, info);
712         if (ret)
713                 goto failed_free_fbmem;
714
715         /*
716          * enable controller clock
717          */
718         clk_enable(fbi->clk);
719
720         pxa168fb_set_par(info);
721
722         /*
723          * Configure default register values.
724          */
725         writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR);
726         writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL);
727         writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1);
728         writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
729         writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
730         writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
731                 fbi->reg_base + LCD_SPU_SRAM_PARA1);
732
733         /*
734          * Allocate color map.
735          */
736         if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
737                 ret = -ENOMEM;
738                 goto failed_free_clk;
739         }
740
741         /*
742          * Register irq handler.
743          */
744         ret = devm_request_irq(&pdev->dev, irq, pxa168fb_handle_irq,
745                                IRQF_SHARED, info->fix.id, fbi);
746         if (ret < 0) {
747                 dev_err(&pdev->dev, "unable to request IRQ\n");
748                 ret = -ENXIO;
749                 goto failed_free_cmap;
750         }
751
752         /*
753          * Enable GFX interrupt
754          */
755         writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA);
756
757         /*
758          * Register framebuffer.
759          */
760         ret = register_framebuffer(info);
761         if (ret < 0) {
762                 dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
763                 ret = -ENXIO;
764                 goto failed_free_cmap;
765         }
766
767         platform_set_drvdata(pdev, fbi);
768         return 0;
769
770 failed_free_cmap:
771         fb_dealloc_cmap(&info->cmap);
772 failed_free_clk:
773         clk_disable(fbi->clk);
774 failed_free_fbmem:
775         dma_free_coherent(fbi->dev, info->fix.smem_len,
776                         info->screen_base, fbi->fb_start_dma);
777 failed_free_info:
778         kfree(info);
779 failed_put_clk:
780         clk_put(clk);
781
782         dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
783         return ret;
784 }
785
786 static int pxa168fb_remove(struct platform_device *pdev)
787 {
788         struct pxa168fb_info *fbi = platform_get_drvdata(pdev);
789         struct fb_info *info;
790         int irq;
791         unsigned int data;
792
793         if (!fbi)
794                 return 0;
795
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);
800
801         info = fbi->info;
802
803         unregister_framebuffer(info);
804
805         writel(GRA_FRAME_IRQ0_ENA(0x0), fbi->reg_base + SPU_IRQ_ENA);
806
807         if (info->cmap.len)
808                 fb_dealloc_cmap(&info->cmap);
809
810         irq = platform_get_irq(pdev, 0);
811
812         dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
813                                 info->screen_base, info->fix.smem_start);
814
815         clk_disable(fbi->clk);
816         clk_put(fbi->clk);
817
818         framebuffer_release(info);
819
820         return 0;
821 }
822
823 static struct platform_driver pxa168fb_driver = {
824         .driver         = {
825                 .name   = "pxa168-fb",
826         },
827         .probe          = pxa168fb_probe,
828         .remove         = pxa168fb_remove,
829 };
830
831 module_platform_driver(pxa168fb_driver);
832
833 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
834               "Green Wan <gwan@marvell.com>");
835 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
836 MODULE_LICENSE("GPL");