Merge tag 'drm-misc-next-2020-02-10' of git://anongit.freedesktop.org/drm/drm-misc...
[platform/kernel/linux-starfive.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
409         /*
410          * Set additional mode info.
411          */
412         if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
413                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
414         else
415                 info->fix.visual = FB_VISUAL_TRUECOLOR;
416         info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
417         info->fix.ypanstep = var->yres;
418
419         /*
420          * Disable panel output while we setup the display.
421          */
422         x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
423         writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
424
425         /*
426          * Configure global panel parameters.
427          */
428         writel((var->yres << 16) | var->xres,
429                 fbi->reg_base + LCD_SPU_V_H_ACTIVE);
430
431         /*
432          * convet var to video mode
433          */
434         fb_var_to_videomode(&mode, &info->var);
435
436         /* Calculate clock divisor. */
437         set_clock_divider(fbi, &mode);
438
439         /* Configure dma ctrl regs. */
440         set_dma_control0(fbi);
441         set_dma_control1(fbi, info->var.sync);
442
443         /*
444          * Configure graphics DMA parameters.
445          */
446         x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH);
447         x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3);
448         writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH);
449         writel((var->yres << 16) | var->xres,
450                 fbi->reg_base + LCD_SPU_GRA_HPXL_VLN);
451         writel((var->yres << 16) | var->xres,
452                 fbi->reg_base + LCD_SPU_GZM_HPXL_VLN);
453
454         /*
455          * Configure dumb panel ctrl regs & timings.
456          */
457         set_dumb_panel_control(info);
458         set_dumb_screen_dimensions(info);
459
460         writel((var->left_margin << 16) | var->right_margin,
461                         fbi->reg_base + LCD_SPU_H_PORCH);
462         writel((var->upper_margin << 16) | var->lower_margin,
463                         fbi->reg_base + LCD_SPU_V_PORCH);
464
465         /*
466          * Re-enable panel output.
467          */
468         x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
469         writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
470
471         return 0;
472 }
473
474 static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
475 {
476         return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
477 }
478
479 static u32 to_rgb(u16 red, u16 green, u16 blue)
480 {
481         red >>= 8;
482         green >>= 8;
483         blue >>= 8;
484
485         return (red << 16) | (green << 8) | blue;
486 }
487
488 static int
489 pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
490                  unsigned int blue, unsigned int trans, struct fb_info *info)
491 {
492         struct pxa168fb_info *fbi = info->par;
493         u32 val;
494
495         if (info->var.grayscale)
496                 red = green = blue = (19595 * red + 38470 * green +
497                                         7471 * blue) >> 16;
498
499         if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
500                 val =  chan_to_field(red,   &info->var.red);
501                 val |= chan_to_field(green, &info->var.green);
502                 val |= chan_to_field(blue , &info->var.blue);
503                 fbi->pseudo_palette[regno] = val;
504         }
505
506         if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
507                 val = to_rgb(red, green, blue);
508                 writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT);
509                 writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL);
510         }
511
512         return 0;
513 }
514
515 static int pxa168fb_blank(int blank, struct fb_info *info)
516 {
517         struct pxa168fb_info *fbi = info->par;
518
519         fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1;
520         set_dumb_panel_control(info);
521
522         return 0;
523 }
524
525 static int pxa168fb_pan_display(struct fb_var_screeninfo *var,
526                                 struct fb_info *info)
527 {
528         set_graphics_start(info, var->xoffset, var->yoffset);
529
530         return 0;
531 }
532
533 static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id)
534 {
535         struct pxa168fb_info *fbi = dev_id;
536         u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR);
537
538         if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) {
539
540                 writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK),
541                         fbi->reg_base + SPU_IRQ_ISR);
542
543                 return IRQ_HANDLED;
544         }
545         return IRQ_NONE;
546 }
547
548 static const struct fb_ops pxa168fb_ops = {
549         .owner          = THIS_MODULE,
550         .fb_check_var   = pxa168fb_check_var,
551         .fb_set_par     = pxa168fb_set_par,
552         .fb_setcolreg   = pxa168fb_setcolreg,
553         .fb_blank       = pxa168fb_blank,
554         .fb_pan_display = pxa168fb_pan_display,
555         .fb_fillrect    = cfb_fillrect,
556         .fb_copyarea    = cfb_copyarea,
557         .fb_imageblit   = cfb_imageblit,
558 };
559
560 static int pxa168fb_init_mode(struct fb_info *info,
561                               struct pxa168fb_mach_info *mi)
562 {
563         struct pxa168fb_info *fbi = info->par;
564         struct fb_var_screeninfo *var = &info->var;
565         int ret = 0;
566         u32 total_w, total_h, refresh;
567         u64 div_result;
568         const struct fb_videomode *m;
569
570         /*
571          * Set default value
572          */
573         refresh = DEFAULT_REFRESH;
574
575         /* try to find best video mode. */
576         m = fb_find_best_mode(&info->var, &info->modelist);
577         if (m)
578                 fb_videomode_to_var(&info->var, m);
579
580         /* Init settings. */
581         var->xres_virtual = var->xres;
582         var->yres_virtual = info->fix.smem_len /
583                 (var->xres_virtual * (var->bits_per_pixel >> 3));
584         dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n",
585                                 var->xres, var->yres);
586
587         /* correct pixclock. */
588         total_w = var->xres + var->left_margin + var->right_margin +
589                   var->hsync_len;
590         total_h = var->yres + var->upper_margin + var->lower_margin +
591                   var->vsync_len;
592
593         div_result = 1000000000000ll;
594         do_div(div_result, total_w * total_h * refresh);
595         var->pixclock = (u32)div_result;
596
597         return ret;
598 }
599
600 static int pxa168fb_probe(struct platform_device *pdev)
601 {
602         struct pxa168fb_mach_info *mi;
603         struct fb_info *info = 0;
604         struct pxa168fb_info *fbi = 0;
605         struct resource *res;
606         struct clk *clk;
607         int irq, ret;
608
609         mi = dev_get_platdata(&pdev->dev);
610         if (mi == NULL) {
611                 dev_err(&pdev->dev, "no platform data defined\n");
612                 return -EINVAL;
613         }
614
615         clk = devm_clk_get(&pdev->dev, "LCDCLK");
616         if (IS_ERR(clk)) {
617                 dev_err(&pdev->dev, "unable to get LCDCLK");
618                 return PTR_ERR(clk);
619         }
620
621         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
622         if (res == NULL) {
623                 dev_err(&pdev->dev, "no IO memory defined\n");
624                 return -ENOENT;
625         }
626
627         irq = platform_get_irq(pdev, 0);
628         if (irq < 0) {
629                 dev_err(&pdev->dev, "no IRQ defined\n");
630                 return -ENOENT;
631         }
632
633         info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
634         if (info == NULL) {
635                 return -ENOMEM;
636         }
637
638         /* Initialize private data */
639         fbi = info->par;
640         fbi->info = info;
641         fbi->clk = clk;
642         fbi->dev = info->dev = &pdev->dev;
643         fbi->panel_rbswap = mi->panel_rbswap;
644         fbi->is_blanked = 0;
645         fbi->active = mi->active;
646
647         /*
648          * Initialise static fb parameters.
649          */
650         info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
651                       FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
652         info->node = -1;
653         strlcpy(info->fix.id, mi->id, 16);
654         info->fix.type = FB_TYPE_PACKED_PIXELS;
655         info->fix.type_aux = 0;
656         info->fix.xpanstep = 0;
657         info->fix.ypanstep = 0;
658         info->fix.ywrapstep = 0;
659         info->fix.mmio_start = res->start;
660         info->fix.mmio_len = resource_size(res);
661         info->fix.accel = FB_ACCEL_NONE;
662         info->fbops = &pxa168fb_ops;
663         info->pseudo_palette = fbi->pseudo_palette;
664
665         /*
666          * Map LCD controller registers.
667          */
668         fbi->reg_base = devm_ioremap(&pdev->dev, res->start,
669                                              resource_size(res));
670         if (fbi->reg_base == NULL) {
671                 ret = -ENOMEM;
672                 goto failed_free_info;
673         }
674
675         /*
676          * Allocate framebuffer memory.
677          */
678         info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
679
680         info->screen_base = dma_alloc_wc(fbi->dev, info->fix.smem_len,
681                                          &fbi->fb_start_dma, GFP_KERNEL);
682         if (info->screen_base == NULL) {
683                 ret = -ENOMEM;
684                 goto failed_free_info;
685         }
686
687         info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
688         set_graphics_start(info, 0, 0);
689
690         /*
691          * Set video mode according to platform data.
692          */
693         set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1);
694
695         fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist);
696
697         /*
698          * init video mode data.
699          */
700         pxa168fb_init_mode(info, mi);
701
702         /*
703          * Fill in sane defaults.
704          */
705         ret = pxa168fb_check_var(&info->var, info);
706         if (ret)
707                 goto failed_free_fbmem;
708
709         /*
710          * enable controller clock
711          */
712         clk_prepare_enable(fbi->clk);
713
714         pxa168fb_set_par(info);
715
716         /*
717          * Configure default register values.
718          */
719         writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR);
720         writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL);
721         writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1);
722         writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
723         writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
724         writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
725                 fbi->reg_base + LCD_SPU_SRAM_PARA1);
726
727         /*
728          * Allocate color map.
729          */
730         if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
731                 ret = -ENOMEM;
732                 goto failed_free_clk;
733         }
734
735         /*
736          * Register irq handler.
737          */
738         ret = devm_request_irq(&pdev->dev, irq, pxa168fb_handle_irq,
739                                IRQF_SHARED, info->fix.id, fbi);
740         if (ret < 0) {
741                 dev_err(&pdev->dev, "unable to request IRQ\n");
742                 ret = -ENXIO;
743                 goto failed_free_cmap;
744         }
745
746         /*
747          * Enable GFX interrupt
748          */
749         writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA);
750
751         /*
752          * Register framebuffer.
753          */
754         ret = register_framebuffer(info);
755         if (ret < 0) {
756                 dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
757                 ret = -ENXIO;
758                 goto failed_free_cmap;
759         }
760
761         platform_set_drvdata(pdev, fbi);
762         return 0;
763
764 failed_free_cmap:
765         fb_dealloc_cmap(&info->cmap);
766 failed_free_clk:
767         clk_disable_unprepare(fbi->clk);
768 failed_free_fbmem:
769         dma_free_wc(fbi->dev, info->fix.smem_len,
770                     info->screen_base, fbi->fb_start_dma);
771 failed_free_info:
772         framebuffer_release(info);
773
774         dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret);
775         return ret;
776 }
777
778 static int pxa168fb_remove(struct platform_device *pdev)
779 {
780         struct pxa168fb_info *fbi = platform_get_drvdata(pdev);
781         struct fb_info *info;
782         int irq;
783         unsigned int data;
784
785         if (!fbi)
786                 return 0;
787
788         /* disable DMA transfer */
789         data = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
790         data &= ~CFG_GRA_ENA_MASK;
791         writel(data, fbi->reg_base + LCD_SPU_DMA_CTRL0);
792
793         info = fbi->info;
794
795         unregister_framebuffer(info);
796
797         writel(GRA_FRAME_IRQ0_ENA(0x0), fbi->reg_base + SPU_IRQ_ENA);
798
799         if (info->cmap.len)
800                 fb_dealloc_cmap(&info->cmap);
801
802         irq = platform_get_irq(pdev, 0);
803
804         dma_free_wc(fbi->dev, info->fix.smem_len,
805                     info->screen_base, info->fix.smem_start);
806
807         clk_disable_unprepare(fbi->clk);
808
809         framebuffer_release(info);
810
811         return 0;
812 }
813
814 static struct platform_driver pxa168fb_driver = {
815         .driver         = {
816                 .name   = "pxa168-fb",
817         },
818         .probe          = pxa168fb_probe,
819         .remove         = pxa168fb_remove,
820 };
821
822 module_platform_driver(pxa168fb_driver);
823
824 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
825               "Green Wan <gwan@marvell.com>");
826 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
827 MODULE_LICENSE("GPL");