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/ioport.h>
25 #include <linux/platform_device.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/clk.h>
28 #include <linux/err.h>
29 #include <linux/uaccess.h>
30 #include <video/pxa168fb.h>
31 
32 #include "pxa168fb.h"
33 
34 #define DEFAULT_REFRESH		60	/* Hz */
35 
determine_best_pix_fmt(struct fb_var_screeninfo * var)36 static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
37 {
38 	/*
39 	 * Pseudocolor mode?
40 	 */
41 	if (var->bits_per_pixel == 8)
42 		return PIX_FMT_PSEUDOCOLOR;
43 
44 	/*
45 	 * Check for 565/1555.
46 	 */
47 	if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
48 	    var->green.length <= 6 && var->blue.length <= 5) {
49 		if (var->transp.length == 0) {
50 			if (var->red.offset >= var->blue.offset)
51 				return PIX_FMT_RGB565;
52 			else
53 				return PIX_FMT_BGR565;
54 		}
55 
56 		if (var->transp.length == 1 && var->green.length <= 5) {
57 			if (var->red.offset >= var->blue.offset)
58 				return PIX_FMT_RGB1555;
59 			else
60 				return PIX_FMT_BGR1555;
61 		}
62 
63 		/* fall through */
64 	}
65 
66 	/*
67 	 * Check for 888/A888.
68 	 */
69 	if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
70 	    var->green.length <= 8 && var->blue.length <= 8) {
71 		if (var->bits_per_pixel == 24 && var->transp.length == 0) {
72 			if (var->red.offset >= var->blue.offset)
73 				return PIX_FMT_RGB888PACK;
74 			else
75 				return PIX_FMT_BGR888PACK;
76 		}
77 
78 		if (var->bits_per_pixel == 32 && var->transp.length == 8) {
79 			if (var->red.offset >= var->blue.offset)
80 				return PIX_FMT_RGBA888;
81 			else
82 				return PIX_FMT_BGRA888;
83 		} else {
84 			if (var->red.offset >= var->blue.offset)
85 				return PIX_FMT_RGB888UNPACK;
86 			else
87 				return PIX_FMT_BGR888UNPACK;
88 		}
89 
90 		/* fall through */
91 	}
92 
93 	return -EINVAL;
94 }
95 
set_pix_fmt(struct fb_var_screeninfo * var,int pix_fmt)96 static void set_pix_fmt(struct fb_var_screeninfo *var, int pix_fmt)
97 {
98 	switch (pix_fmt) {
99 	case PIX_FMT_RGB565:
100 		var->bits_per_pixel = 16;
101 		var->red.offset = 11;    var->red.length = 5;
102 		var->green.offset = 5;   var->green.length = 6;
103 		var->blue.offset = 0;    var->blue.length = 5;
104 		var->transp.offset = 0;  var->transp.length = 0;
105 		break;
106 	case PIX_FMT_BGR565:
107 		var->bits_per_pixel = 16;
108 		var->red.offset = 0;     var->red.length = 5;
109 		var->green.offset = 5;   var->green.length = 6;
110 		var->blue.offset = 11;   var->blue.length = 5;
111 		var->transp.offset = 0;  var->transp.length = 0;
112 		break;
113 	case PIX_FMT_RGB1555:
114 		var->bits_per_pixel = 16;
115 		var->red.offset = 10;    var->red.length = 5;
116 		var->green.offset = 5;   var->green.length = 5;
117 		var->blue.offset = 0;    var->blue.length = 5;
118 		var->transp.offset = 15; var->transp.length = 1;
119 		break;
120 	case PIX_FMT_BGR1555:
121 		var->bits_per_pixel = 16;
122 		var->red.offset = 0;     var->red.length = 5;
123 		var->green.offset = 5;   var->green.length = 5;
124 		var->blue.offset = 10;   var->blue.length = 5;
125 		var->transp.offset = 15; var->transp.length = 1;
126 		break;
127 	case PIX_FMT_RGB888PACK:
128 		var->bits_per_pixel = 24;
129 		var->red.offset = 16;    var->red.length = 8;
130 		var->green.offset = 8;   var->green.length = 8;
131 		var->blue.offset = 0;    var->blue.length = 8;
132 		var->transp.offset = 0;  var->transp.length = 0;
133 		break;
134 	case PIX_FMT_BGR888PACK:
135 		var->bits_per_pixel = 24;
136 		var->red.offset = 0;     var->red.length = 8;
137 		var->green.offset = 8;   var->green.length = 8;
138 		var->blue.offset = 16;   var->blue.length = 8;
139 		var->transp.offset = 0;  var->transp.length = 0;
140 		break;
141 	case PIX_FMT_RGBA888:
142 		var->bits_per_pixel = 32;
143 		var->red.offset = 16;    var->red.length = 8;
144 		var->green.offset = 8;   var->green.length = 8;
145 		var->blue.offset = 0;    var->blue.length = 8;
146 		var->transp.offset = 24; var->transp.length = 8;
147 		break;
148 	case PIX_FMT_BGRA888:
149 		var->bits_per_pixel = 32;
150 		var->red.offset = 0;     var->red.length = 8;
151 		var->green.offset = 8;   var->green.length = 8;
152 		var->blue.offset = 16;   var->blue.length = 8;
153 		var->transp.offset = 24; var->transp.length = 8;
154 		break;
155 	case PIX_FMT_PSEUDOCOLOR:
156 		var->bits_per_pixel = 8;
157 		var->red.offset = 0;     var->red.length = 8;
158 		var->green.offset = 0;   var->green.length = 8;
159 		var->blue.offset = 0;    var->blue.length = 8;
160 		var->transp.offset = 0;  var->transp.length = 0;
161 		break;
162 	}
163 }
164 
set_mode(struct pxa168fb_info * fbi,struct fb_var_screeninfo * var,struct fb_videomode * mode,int pix_fmt,int ystretch)165 static void set_mode(struct pxa168fb_info *fbi, struct fb_var_screeninfo *var,
166 		     struct fb_videomode *mode, int pix_fmt, int ystretch)
167 {
168 	struct fb_info *info = fbi->info;
169 
170 	set_pix_fmt(var, pix_fmt);
171 
172 	var->xres = mode->xres;
173 	var->yres = mode->yres;
174 	var->xres_virtual = max(var->xres, var->xres_virtual);
175 	if (ystretch)
176 		var->yres_virtual = info->fix.smem_len /
177 			(var->xres_virtual * (var->bits_per_pixel >> 3));
178 	else
179 		var->yres_virtual = max(var->yres, var->yres_virtual);
180 	var->grayscale = 0;
181 	var->accel_flags = FB_ACCEL_NONE;
182 	var->pixclock = mode->pixclock;
183 	var->left_margin = mode->left_margin;
184 	var->right_margin = mode->right_margin;
185 	var->upper_margin = mode->upper_margin;
186 	var->lower_margin = mode->lower_margin;
187 	var->hsync_len = mode->hsync_len;
188 	var->vsync_len = mode->vsync_len;
189 	var->sync = mode->sync;
190 	var->vmode = FB_VMODE_NONINTERLACED;
191 	var->rotate = FB_ROTATE_UR;
192 }
193 
pxa168fb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)194 static int pxa168fb_check_var(struct fb_var_screeninfo *var,
195 			      struct fb_info *info)
196 {
197 	struct pxa168fb_info *fbi = info->par;
198 	int pix_fmt;
199 
200 	/*
201 	 * Determine which pixel format we're going to use.
202 	 */
203 	pix_fmt = determine_best_pix_fmt(var);
204 	if (pix_fmt < 0)
205 		return pix_fmt;
206 	set_pix_fmt(var, pix_fmt);
207 	fbi->pix_fmt = pix_fmt;
208 
209 	/*
210 	 * Basic geometry sanity checks.
211 	 */
212 	if (var->xoffset + var->xres > var->xres_virtual)
213 		return -EINVAL;
214 	if (var->yoffset + var->yres > var->yres_virtual)
215 		return -EINVAL;
216 	if (var->xres + var->right_margin +
217 	    var->hsync_len + var->left_margin > 2048)
218 		return -EINVAL;
219 	if (var->yres + var->lower_margin +
220 	    var->vsync_len + var->upper_margin > 2048)
221 		return -EINVAL;
222 
223 	/*
224 	 * Check size of framebuffer.
225 	 */
226 	if (var->xres_virtual * var->yres_virtual *
227 	    (var->bits_per_pixel >> 3) > info->fix.smem_len)
228 		return -EINVAL;
229 
230 	return 0;
231 }
232 
233 /*
234  * The hardware clock divider has an integer and a fractional
235  * stage:
236  *
237  *	clk2 = clk_in / integer_divider
238  *	clk_out = clk2 * (1 - (fractional_divider >> 12))
239  *
240  * Calculate integer and fractional divider for given clk_in
241  * and clk_out.
242  */
set_clock_divider(struct pxa168fb_info * fbi,const struct fb_videomode * m)243 static void set_clock_divider(struct pxa168fb_info *fbi,
244 			      const struct fb_videomode *m)
245 {
246 	int divider_int;
247 	int needed_pixclk;
248 	u64 div_result;
249 	u32 x = 0;
250 
251 	/*
252 	 * Notice: The field pixclock is used by linux fb
253 	 * is in pixel second. E.g. struct fb_videomode &
254 	 * struct fb_var_screeninfo
255 	 */
256 
257 	/*
258 	 * Check input values.
259 	 */
260 	if (!m || !m->pixclock || !m->refresh) {
261 		dev_err(fbi->dev, "Input refresh or pixclock is wrong.\n");
262 		return;
263 	}
264 
265 	/*
266 	 * Using PLL/AXI clock.
267 	 */
268 	x = 0x80000000;
269 
270 	/*
271 	 * Calc divider according to refresh rate.
272 	 */
273 	div_result = 1000000000000ll;
274 	do_div(div_result, m->pixclock);
275 	needed_pixclk = (u32)div_result;
276 
277 	divider_int = clk_get_rate(fbi->clk) / needed_pixclk;
278 
279 	/* check whether divisor is too small. */
280 	if (divider_int < 2) {
281 		dev_warn(fbi->dev, "Warning: clock source is too slow."
282 				"Try smaller resolution\n");
283 		divider_int = 2;
284 	}
285 
286 	/*
287 	 * Set setting to reg.
288 	 */
289 	x |= divider_int;
290 	writel(x, fbi->reg_base + LCD_CFG_SCLK_DIV);
291 }
292 
set_dma_control0(struct pxa168fb_info * fbi)293 static void set_dma_control0(struct pxa168fb_info *fbi)
294 {
295 	u32 x;
296 
297 	/*
298 	 * Set bit to enable graphics DMA.
299 	 */
300 	x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
301 	x &= ~CFG_GRA_ENA_MASK;
302 	x |= fbi->active ? CFG_GRA_ENA(1) : CFG_GRA_ENA(0);
303 
304 	/*
305 	 * If we are in a pseudo-color mode, we need to enable
306 	 * palette lookup.
307 	 */
308 	if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
309 		x |= 0x10000000;
310 
311 	/*
312 	 * Configure hardware pixel format.
313 	 */
314 	x &= ~(0xF << 16);
315 	x |= (fbi->pix_fmt >> 1) << 16;
316 
317 	/*
318 	 * Check red and blue pixel swap.
319 	 * 1. source data swap
320 	 * 2. panel output data swap
321 	 */
322 	x &= ~(1 << 12);
323 	x |= ((fbi->pix_fmt & 1) ^ (fbi->panel_rbswap)) << 12;
324 
325 	writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL0);
326 }
327 
set_dma_control1(struct pxa168fb_info * fbi,int sync)328 static void set_dma_control1(struct pxa168fb_info *fbi, int sync)
329 {
330 	u32 x;
331 
332 	/*
333 	 * Configure default bits: vsync triggers DMA, gated clock
334 	 * enable, power save enable, configure alpha registers to
335 	 * display 100% graphics, and set pixel command.
336 	 */
337 	x = readl(fbi->reg_base + LCD_SPU_DMA_CTRL1);
338 	x |= 0x2032ff81;
339 
340 	/*
341 	 * We trigger DMA on the falling edge of vsync if vsync is
342 	 * active low, or on the rising edge if vsync is active high.
343 	 */
344 	if (!(sync & FB_SYNC_VERT_HIGH_ACT))
345 		x |= 0x08000000;
346 
347 	writel(x, fbi->reg_base + LCD_SPU_DMA_CTRL1);
348 }
349 
set_graphics_start(struct fb_info * info,int xoffset,int yoffset)350 static void set_graphics_start(struct fb_info *info, int xoffset, int yoffset)
351 {
352 	struct pxa168fb_info *fbi = info->par;
353 	struct fb_var_screeninfo *var = &info->var;
354 	int pixel_offset;
355 	unsigned long addr;
356 
357 	pixel_offset = (yoffset * var->xres_virtual) + xoffset;
358 
359 	addr = fbi->fb_start_dma + (pixel_offset * (var->bits_per_pixel >> 3));
360 	writel(addr, fbi->reg_base + LCD_CFG_GRA_START_ADDR0);
361 }
362 
set_dumb_panel_control(struct fb_info * info)363 static void set_dumb_panel_control(struct fb_info *info)
364 {
365 	struct pxa168fb_info *fbi = info->par;
366 	struct pxa168fb_mach_info *mi = fbi->dev->platform_data;
367 	u32 x;
368 
369 	/*
370 	 * Preserve enable flag.
371 	 */
372 	x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL) & 0x00000001;
373 
374 	x |= (fbi->is_blanked ? 0x7 : mi->dumb_mode) << 28;
375 	x |= mi->gpio_output_data << 20;
376 	x |= mi->gpio_output_mask << 12;
377 	x |= mi->panel_rgb_reverse_lanes ? 0x00000080 : 0;
378 	x |= mi->invert_composite_blank ? 0x00000040 : 0;
379 	x |= (info->var.sync & FB_SYNC_COMP_HIGH_ACT) ? 0x00000020 : 0;
380 	x |= mi->invert_pix_val_ena ? 0x00000010 : 0;
381 	x |= (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x00000008;
382 	x |= (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x00000004;
383 	x |= mi->invert_pixclock ? 0x00000002 : 0;
384 
385 	writel(x, fbi->reg_base + LCD_SPU_DUMB_CTRL);
386 }
387 
set_dumb_screen_dimensions(struct fb_info * info)388 static void set_dumb_screen_dimensions(struct fb_info *info)
389 {
390 	struct pxa168fb_info *fbi = info->par;
391 	struct fb_var_screeninfo *v = &info->var;
392 	int x;
393 	int y;
394 
395 	x = v->xres + v->right_margin + v->hsync_len + v->left_margin;
396 	y = v->yres + v->lower_margin + v->vsync_len + v->upper_margin;
397 
398 	writel((y << 16) | x, fbi->reg_base + LCD_SPUT_V_H_TOTAL);
399 }
400 
pxa168fb_set_par(struct fb_info * info)401 static int pxa168fb_set_par(struct fb_info *info)
402 {
403 	struct pxa168fb_info *fbi = info->par;
404 	struct fb_var_screeninfo *var = &info->var;
405 	struct fb_videomode mode;
406 	u32 x;
407 	struct pxa168fb_mach_info *mi;
408 
409 	mi = fbi->dev->platform_data;
410 
411 	/*
412 	 * Set additional mode info.
413 	 */
414 	if (fbi->pix_fmt == PIX_FMT_PSEUDOCOLOR)
415 		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
416 	else
417 		info->fix.visual = FB_VISUAL_TRUECOLOR;
418 	info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
419 	info->fix.ypanstep = var->yres;
420 
421 	/*
422 	 * Disable panel output while we setup the display.
423 	 */
424 	x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
425 	writel(x & ~1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
426 
427 	/*
428 	 * Configure global panel parameters.
429 	 */
430 	writel((var->yres << 16) | var->xres,
431 		fbi->reg_base + LCD_SPU_V_H_ACTIVE);
432 
433 	/*
434 	 * convet var to video mode
435 	 */
436 	fb_var_to_videomode(&mode, &info->var);
437 
438 	/* Calculate clock divisor. */
439 	set_clock_divider(fbi, &mode);
440 
441 	/* Configure dma ctrl regs. */
442 	set_dma_control0(fbi);
443 	set_dma_control1(fbi, info->var.sync);
444 
445 	/*
446 	 * Configure graphics DMA parameters.
447 	 */
448 	x = readl(fbi->reg_base + LCD_CFG_GRA_PITCH);
449 	x = (x & ~0xFFFF) | ((var->xres_virtual * var->bits_per_pixel) >> 3);
450 	writel(x, fbi->reg_base + LCD_CFG_GRA_PITCH);
451 	writel((var->yres << 16) | var->xres,
452 		fbi->reg_base + LCD_SPU_GRA_HPXL_VLN);
453 	writel((var->yres << 16) | var->xres,
454 		fbi->reg_base + LCD_SPU_GZM_HPXL_VLN);
455 
456 	/*
457 	 * Configure dumb panel ctrl regs & timings.
458 	 */
459 	set_dumb_panel_control(info);
460 	set_dumb_screen_dimensions(info);
461 
462 	writel((var->left_margin << 16) | var->right_margin,
463 			fbi->reg_base + LCD_SPU_H_PORCH);
464 	writel((var->upper_margin << 16) | var->lower_margin,
465 			fbi->reg_base + LCD_SPU_V_PORCH);
466 
467 	/*
468 	 * Re-enable panel output.
469 	 */
470 	x = readl(fbi->reg_base + LCD_SPU_DUMB_CTRL);
471 	writel(x | 1, fbi->reg_base + LCD_SPU_DUMB_CTRL);
472 
473 	return 0;
474 }
475 
chan_to_field(unsigned int chan,struct fb_bitfield * bf)476 static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
477 {
478 	return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
479 }
480 
to_rgb(u16 red,u16 green,u16 blue)481 static u32 to_rgb(u16 red, u16 green, u16 blue)
482 {
483 	red >>= 8;
484 	green >>= 8;
485 	blue >>= 8;
486 
487 	return (red << 16) | (green << 8) | blue;
488 }
489 
490 static int
pxa168fb_setcolreg(unsigned int regno,unsigned int red,unsigned int green,unsigned int blue,unsigned int trans,struct fb_info * info)491 pxa168fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
492 		 unsigned int blue, unsigned int trans, struct fb_info *info)
493 {
494 	struct pxa168fb_info *fbi = info->par;
495 	u32 val;
496 
497 	if (info->var.grayscale)
498 		red = green = blue = (19595 * red + 38470 * green +
499 					7471 * blue) >> 16;
500 
501 	if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
502 		val =  chan_to_field(red,   &info->var.red);
503 		val |= chan_to_field(green, &info->var.green);
504 		val |= chan_to_field(blue , &info->var.blue);
505 		fbi->pseudo_palette[regno] = val;
506 	}
507 
508 	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
509 		val = to_rgb(red, green, blue);
510 		writel(val, fbi->reg_base + LCD_SPU_SRAM_WRDAT);
511 		writel(0x8300 | regno, fbi->reg_base + LCD_SPU_SRAM_CTRL);
512 	}
513 
514 	return 0;
515 }
516 
pxa168fb_blank(int blank,struct fb_info * info)517 static int pxa168fb_blank(int blank, struct fb_info *info)
518 {
519 	struct pxa168fb_info *fbi = info->par;
520 
521 	fbi->is_blanked = (blank == FB_BLANK_UNBLANK) ? 0 : 1;
522 	set_dumb_panel_control(info);
523 
524 	return 0;
525 }
526 
pxa168fb_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)527 static int pxa168fb_pan_display(struct fb_var_screeninfo *var,
528 				struct fb_info *info)
529 {
530 	set_graphics_start(info, var->xoffset, var->yoffset);
531 
532 	return 0;
533 }
534 
pxa168fb_handle_irq(int irq,void * dev_id)535 static irqreturn_t pxa168fb_handle_irq(int irq, void *dev_id)
536 {
537 	struct pxa168fb_info *fbi = dev_id;
538 	u32 isr = readl(fbi->reg_base + SPU_IRQ_ISR);
539 
540 	if ((isr & GRA_FRAME_IRQ0_ENA_MASK)) {
541 
542 		writel(isr & (~GRA_FRAME_IRQ0_ENA_MASK),
543 			fbi->reg_base + SPU_IRQ_ISR);
544 
545 		return IRQ_HANDLED;
546 	}
547 	return IRQ_NONE;
548 }
549 
550 static struct fb_ops pxa168fb_ops = {
551 	.owner		= THIS_MODULE,
552 	.fb_check_var	= pxa168fb_check_var,
553 	.fb_set_par	= pxa168fb_set_par,
554 	.fb_setcolreg	= pxa168fb_setcolreg,
555 	.fb_blank	= pxa168fb_blank,
556 	.fb_pan_display	= pxa168fb_pan_display,
557 	.fb_fillrect	= cfb_fillrect,
558 	.fb_copyarea	= cfb_copyarea,
559 	.fb_imageblit	= cfb_imageblit,
560 };
561 
pxa168fb_init_mode(struct fb_info * info,struct pxa168fb_mach_info * mi)562 static int __devinit pxa168fb_init_mode(struct fb_info *info,
563 			      struct pxa168fb_mach_info *mi)
564 {
565 	struct pxa168fb_info *fbi = info->par;
566 	struct fb_var_screeninfo *var = &info->var;
567 	int ret = 0;
568 	u32 total_w, total_h, refresh;
569 	u64 div_result;
570 	const struct fb_videomode *m;
571 
572 	/*
573 	 * Set default value
574 	 */
575 	refresh = DEFAULT_REFRESH;
576 
577 	/* try to find best video mode. */
578 	m = fb_find_best_mode(&info->var, &info->modelist);
579 	if (m)
580 		fb_videomode_to_var(&info->var, m);
581 
582 	/* Init settings. */
583 	var->xres_virtual = var->xres;
584 	var->yres_virtual = info->fix.smem_len /
585 		(var->xres_virtual * (var->bits_per_pixel >> 3));
586 	dev_dbg(fbi->dev, "pxa168fb: find best mode: res = %dx%d\n",
587 				var->xres, var->yres);
588 
589 	/* correct pixclock. */
590 	total_w = var->xres + var->left_margin + var->right_margin +
591 		  var->hsync_len;
592 	total_h = var->yres + var->upper_margin + var->lower_margin +
593 		  var->vsync_len;
594 
595 	div_result = 1000000000000ll;
596 	do_div(div_result, total_w * total_h * refresh);
597 	var->pixclock = (u32)div_result;
598 
599 	return ret;
600 }
601 
pxa168fb_probe(struct platform_device * pdev)602 static int __devinit pxa168fb_probe(struct platform_device *pdev)
603 {
604 	struct pxa168fb_mach_info *mi;
605 	struct fb_info *info = 0;
606 	struct pxa168fb_info *fbi = 0;
607 	struct resource *res;
608 	struct clk *clk;
609 	int irq, ret;
610 
611 	mi = pdev->dev.platform_data;
612 	if (mi == NULL) {
613 		dev_err(&pdev->dev, "no platform data defined\n");
614 		return -EINVAL;
615 	}
616 
617 	clk = clk_get(&pdev->dev, "LCDCLK");
618 	if (IS_ERR(clk)) {
619 		dev_err(&pdev->dev, "unable to get LCDCLK");
620 		return PTR_ERR(clk);
621 	}
622 
623 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
624 	if (res == NULL) {
625 		dev_err(&pdev->dev, "no IO memory defined\n");
626 		ret = -ENOENT;
627 		goto failed_put_clk;
628 	}
629 
630 	irq = platform_get_irq(pdev, 0);
631 	if (irq < 0) {
632 		dev_err(&pdev->dev, "no IRQ defined\n");
633 		ret = -ENOENT;
634 		goto failed_put_clk;
635 	}
636 
637 	info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev);
638 	if (info == NULL) {
639 		ret = -ENOMEM;
640 		goto failed_put_clk;
641 	}
642 
643 	/* Initialize private data */
644 	fbi = info->par;
645 	fbi->info = info;
646 	fbi->clk = clk;
647 	fbi->dev = info->dev = &pdev->dev;
648 	fbi->panel_rbswap = mi->panel_rbswap;
649 	fbi->is_blanked = 0;
650 	fbi->active = mi->active;
651 
652 	/*
653 	 * Initialise static fb parameters.
654 	 */
655 	info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
656 		      FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
657 	info->node = -1;
658 	strlcpy(info->fix.id, mi->id, 16);
659 	info->fix.type = FB_TYPE_PACKED_PIXELS;
660 	info->fix.type_aux = 0;
661 	info->fix.xpanstep = 0;
662 	info->fix.ypanstep = 0;
663 	info->fix.ywrapstep = 0;
664 	info->fix.mmio_start = res->start;
665 	info->fix.mmio_len = resource_size(res);
666 	info->fix.accel = FB_ACCEL_NONE;
667 	info->fbops = &pxa168fb_ops;
668 	info->pseudo_palette = fbi->pseudo_palette;
669 
670 	/*
671 	 * Map LCD controller registers.
672 	 */
673 	fbi->reg_base = ioremap_nocache(res->start, resource_size(res));
674 	if (fbi->reg_base == NULL) {
675 		ret = -ENOMEM;
676 		goto failed_free_info;
677 	}
678 
679 	/*
680 	 * Allocate framebuffer memory.
681 	 */
682 	info->fix.smem_len = PAGE_ALIGN(DEFAULT_FB_SIZE);
683 
684 	info->screen_base = dma_alloc_writecombine(fbi->dev, info->fix.smem_len,
685 						&fbi->fb_start_dma, GFP_KERNEL);
686 	if (info->screen_base == NULL) {
687 		ret = -ENOMEM;
688 		goto failed_free_info;
689 	}
690 
691 	info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
692 	set_graphics_start(info, 0, 0);
693 
694 	/*
695 	 * Set video mode according to platform data.
696 	 */
697 	set_mode(fbi, &info->var, mi->modes, mi->pix_fmt, 1);
698 
699 	fb_videomode_to_modelist(mi->modes, mi->num_modes, &info->modelist);
700 
701 	/*
702 	 * init video mode data.
703 	 */
704 	pxa168fb_init_mode(info, mi);
705 
706 	/*
707 	 * Fill in sane defaults.
708 	 */
709 	ret = pxa168fb_check_var(&info->var, info);
710 	if (ret)
711 		goto failed_free_fbmem;
712 
713 	/*
714 	 * enable controller clock
715 	 */
716 	clk_enable(fbi->clk);
717 
718 	pxa168fb_set_par(info);
719 
720 	/*
721 	 * Configure default register values.
722 	 */
723 	writel(0, fbi->reg_base + LCD_SPU_BLANKCOLOR);
724 	writel(mi->io_pin_allocation_mode, fbi->reg_base + SPU_IOPAD_CONTROL);
725 	writel(0, fbi->reg_base + LCD_CFG_GRA_START_ADDR1);
726 	writel(0, fbi->reg_base + LCD_SPU_GRA_OVSA_HPXL_VLN);
727 	writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
728 	writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
729 		fbi->reg_base + LCD_SPU_SRAM_PARA1);
730 
731 	/*
732 	 * Allocate color map.
733 	 */
734 	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
735 		ret = -ENOMEM;
736 		goto failed_free_clk;
737 	}
738 
739 	/*
740 	 * Register irq handler.
741 	 */
742 	ret = request_irq(irq, pxa168fb_handle_irq, IRQF_SHARED,
743 					info->fix.id, fbi);
744 	if (ret < 0) {
745 		dev_err(&pdev->dev, "unable to request IRQ\n");
746 		ret = -ENXIO;
747 		goto failed_free_cmap;
748 	}
749 
750 	/*
751 	 * Enable GFX interrupt
752 	 */
753 	writel(GRA_FRAME_IRQ0_ENA(0x1), fbi->reg_base + SPU_IRQ_ENA);
754 
755 	/*
756 	 * Register framebuffer.
757 	 */
758 	ret = register_framebuffer(info);
759 	if (ret < 0) {
760 		dev_err(&pdev->dev, "Failed to register pxa168-fb: %d\n", ret);
761 		ret = -ENXIO;
762 		goto failed_free_irq;
763 	}
764 
765 	platform_set_drvdata(pdev, fbi);
766 	return 0;
767 
768 failed_free_irq:
769 	free_irq(irq, fbi);
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 
pxa168fb_remove(struct platform_device * pdev)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 
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 	free_irq(irq, fbi);
812 
813 	dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
814 				info->screen_base, info->fix.smem_start);
815 
816 	iounmap(fbi->reg_base);
817 
818 	clk_disable(fbi->clk);
819 	clk_put(fbi->clk);
820 
821 	framebuffer_release(info);
822 
823 	return 0;
824 }
825 
826 static struct platform_driver pxa168fb_driver = {
827 	.driver		= {
828 		.name	= "pxa168-fb",
829 		.owner	= THIS_MODULE,
830 	},
831 	.probe		= pxa168fb_probe,
832 	.remove		= __devexit_p(pxa168fb_remove),
833 };
834 
835 module_platform_driver(pxa168fb_driver);
836 
837 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
838 	      "Green Wan <gwan@marvell.com>");
839 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
840 MODULE_LICENSE("GPL");
841