Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pxa168fb.c
Go to the documentation of this file.
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 <[email protected]>
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;
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));
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 = fbi->dev->platform_data;
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 = fbi->dev->platform_data;
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,
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,
454  writel((var->yres << 16) | var->xres,
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 __devinit 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 __devinit 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 = pdev->dev.platform_data;
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  */
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 
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  */
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  */
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 __devexit 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 
804 
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  .owner = THIS_MODULE,
827  },
828  .probe = pxa168fb_probe,
829  .remove = __devexit_p(pxa168fb_remove),
830 };
831 
832 module_platform_driver(pxa168fb_driver);
833 
834 MODULE_AUTHOR("Lennert Buytenhek <[email protected]> "
835  "Green Wan <[email protected]>");
836 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
837 MODULE_LICENSE("GPL");