Blame view

drivers/video/pxafb.c 61.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   *  linux/drivers/video/pxafb.c
   *
   *  Copyright (C) 1999 Eric A. Thomas.
   *  Copyright (C) 2004 Jean-Frederic Clere.
   *  Copyright (C) 2004 Ian Campbell.
   *  Copyright (C) 2004 Jeff Lackey.
   *   Based on sa1100fb.c Copyright (C) 1999 Eric A. Thomas
   *  which in turn is
   *   Based on acornfb.c Copyright (C) Russell King.
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file COPYING in the main directory of this archive for
   * more details.
   *
   *	        Intel PXA250/210 LCD Controller Frame Buffer Driver
   *
   * Please direct your questions and comments on this driver to the following
   * email address:
   *
   *	linux-arm-kernel@lists.arm.linux.org.uk
   *
198fc108e   Eric Miao   [ARM] pxafb: add ...
23
24
25
26
27
28
29
30
31
32
   * Add support for overlay1 and overlay2 based on pxafb_overlay.c:
   *
   *   Copyright (C) 2004, Intel Corporation
   *
   *     2003/08/27: <yu.tang@intel.com>
   *     2004/03/10: <stanley.cai@intel.com>
   *     2004/10/28: <yan.yin@intel.com>
   *
   *   Copyright (C) 2006-2008 Marvell International Ltd.
   *   All Rights Reserved
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/errno.h>
  #include <linux/string.h>
  #include <linux/interrupt.h>
  #include <linux/slab.h>
27ac792ca   Andrea Righi   PAGE_ALIGN(): cor...
42
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
  #include <linux/fb.h>
  #include <linux/delay.h>
  #include <linux/init.h>
  #include <linux/ioport.h>
  #include <linux/cpufreq.h>
d052d1bef   Russell King   Create platform_d...
48
  #include <linux/platform_device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  #include <linux/dma-mapping.h>
72e3524c0   Russell King   [ARM] pxa: update...
50
51
  #include <linux/clk.h>
  #include <linux/err.h>
2ba162b93   Eric Miao   pxafb: use comple...
52
  #include <linux/completion.h>
b91dbce56   Matthias Kaehlcke   pxafb: convert ct...
53
  #include <linux/mutex.h>
3c42a4491   Eric Miao   pxafb: preliminar...
54
55
  #include <linux/kthread.h>
  #include <linux/freezer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

a09e64fbc   Russell King   [ARM] Move includ...
57
  #include <mach/hardware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  #include <asm/io.h>
  #include <asm/irq.h>
bf1b8ab6f   Nicolas Pitre   [PATCH] ARM: 2721...
60
  #include <asm/div64.h>
a09e64fbc   Russell King   [ARM] Move includ...
61
62
  #include <mach/bitfield.h>
  #include <mach/pxafb.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
68
69
70
71
  
  /*
   * Complain if VAR is out of range.
   */
  #define DEBUG_VAR 1
  
  #include "pxafb.h"
  
  /* Bits which should not be set in machine configuration structures */
b0086efba   eric miao   pxafb: fix variou...
72
73
74
75
76
  #define LCCR0_INVALID_CONFIG_MASK	(LCCR0_OUM | LCCR0_BM | LCCR0_QDM |\
  					 LCCR0_DIS | LCCR0_EFM | LCCR0_IUM |\
  					 LCCR0_SFM | LCCR0_LDM | LCCR0_ENB)
  
  #define LCCR3_INVALID_CONFIG_MASK	(LCCR3_HSP | LCCR3_VSP |\
878f57831   Eric Miao   [ARM] pxafb: clea...
77
  					 LCCR3_PCD | LCCR3_BPP(0xf))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

b0086efba   eric miao   pxafb: fix variou...
79
80
  static int pxafb_activate_var(struct fb_var_screeninfo *var,
  				struct pxafb_info *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
448ac4797   Sven Neumann   pxafb: use passed...
82
83
  static void setup_base_frame(struct pxafb_info *fbi,
                               struct fb_var_screeninfo *var, int branch);
198fc108e   Eric Miao   [ARM] pxafb: add ...
84
85
  static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
  			   unsigned long offset, size_t size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

77e196752   Eric Miao   [ARM] pxafb: allo...
87
  static unsigned long video_mem_size = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88

a7535ba73   Eric Miao   pxafb: introduce ...
89
90
91
92
93
94
95
96
97
98
99
  static inline unsigned long
  lcd_readl(struct pxafb_info *fbi, unsigned int off)
  {
  	return __raw_readl(fbi->mmio_base + off);
  }
  
  static inline void
  lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val)
  {
  	__raw_writel(val, fbi->mmio_base + off);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
107
  static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
  {
  	unsigned long flags;
  
  	local_irq_save(flags);
  	/*
  	 * We need to handle two requests being made at the same time.
  	 * There are two important cases:
b0086efba   eric miao   pxafb: fix variou...
108
109
110
111
112
113
  	 *  1. When we are changing VT (C_REENABLE) while unblanking
  	 *     (C_ENABLE) We must perform the unblanking, which will
  	 *     do our REENABLE for us.
  	 *  2. When we are blanking, but immediately unblank before
  	 *     we have blanked.  We do the "REENABLE" thing here as
  	 *     well, just to be sure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  	 */
  	if (fbi->task_state == C_ENABLE && state == C_REENABLE)
  		state = (u_int) -1;
  	if (fbi->task_state == C_DISABLE && state == C_ENABLE)
  		state = C_REENABLE;
  
  	if (state != (u_int)-1) {
  		fbi->task_state = state;
  		schedule_work(&fbi->task);
  	}
  	local_irq_restore(flags);
  }
  
  static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
  {
  	chan &= 0xffff;
  	chan >>= 16 - bf->length;
  	return chan << bf->offset;
  }
  
  static int
  pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
  		       u_int trans, struct fb_info *info)
  {
  	struct pxafb_info *fbi = (struct pxafb_info *)info;
9ffa73960   Hans J. Koch   pxafb: Add suppor...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  	u_int val;
  
  	if (regno >= fbi->palette_size)
  		return 1;
  
  	if (fbi->fb.var.grayscale) {
  		fbi->palette_cpu[regno] = ((blue >> 8) & 0x00ff);
  		return 0;
  	}
  
  	switch (fbi->lccr4 & LCCR4_PAL_FOR_MASK) {
  	case LCCR4_PAL_FOR_0:
  		val  = ((red   >>  0) & 0xf800);
  		val |= ((green >>  5) & 0x07e0);
  		val |= ((blue  >> 11) & 0x001f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  		fbi->palette_cpu[regno] = val;
9ffa73960   Hans J. Koch   pxafb: Add suppor...
155
156
157
158
159
  		break;
  	case LCCR4_PAL_FOR_1:
  		val  = ((red   << 8) & 0x00f80000);
  		val |= ((green >> 0) & 0x0000fc00);
  		val |= ((blue  >> 8) & 0x000000f8);
b0086efba   eric miao   pxafb: fix variou...
160
  		((u32 *)(fbi->palette_cpu))[regno] = val;
9ffa73960   Hans J. Koch   pxafb: Add suppor...
161
162
163
164
165
  		break;
  	case LCCR4_PAL_FOR_2:
  		val  = ((red   << 8) & 0x00fc0000);
  		val |= ((green >> 0) & 0x0000fc00);
  		val |= ((blue  >> 8) & 0x000000fc);
b0086efba   eric miao   pxafb: fix variou...
166
  		((u32 *)(fbi->palette_cpu))[regno] = val;
9ffa73960   Hans J. Koch   pxafb: Add suppor...
167
  		break;
a0427509a   Eric Miao   [ARM] pxafb: add ...
168
169
170
171
172
173
  	case LCCR4_PAL_FOR_3:
  		val  = ((red   << 8) & 0x00ff0000);
  		val |= ((green >> 0) & 0x0000ff00);
  		val |= ((blue  >> 8) & 0x000000ff);
  		((u32 *)(fbi->palette_cpu))[regno] = val;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	}
9ffa73960   Hans J. Koch   pxafb: Add suppor...
175
176
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  }
  
  static int
  pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  		   u_int trans, struct fb_info *info)
  {
  	struct pxafb_info *fbi = (struct pxafb_info *)info;
  	unsigned int val;
  	int ret = 1;
  
  	/*
  	 * If inverse mode was selected, invert all the colours
  	 * rather than the register number.  The register number
  	 * is what you poke into the framebuffer to produce the
  	 * colour you requested.
  	 */
  	if (fbi->cmap_inverse) {
  		red   = 0xffff - red;
  		green = 0xffff - green;
  		blue  = 0xffff - blue;
  	}
  
  	/*
  	 * If greyscale is true, then we convert the RGB value
  	 * to greyscale no matter what visual we are using.
  	 */
  	if (fbi->fb.var.grayscale)
  		red = green = blue = (19595 * red + 38470 * green +
  					7471 * blue) >> 16;
  
  	switch (fbi->fb.fix.visual) {
  	case FB_VISUAL_TRUECOLOR:
  		/*
  		 * 16-bit True Colour.  We encode the RGB value
  		 * according to the RGB bitfield information.
  		 */
  		if (regno < 16) {
  			u32 *pal = fbi->fb.pseudo_palette;
  
  			val  = chan_to_field(red, &fbi->fb.var.red);
  			val |= chan_to_field(green, &fbi->fb.var.green);
  			val |= chan_to_field(blue, &fbi->fb.var.blue);
  
  			pal[regno] = val;
  			ret = 0;
  		}
  		break;
  
  	case FB_VISUAL_STATIC_PSEUDOCOLOR:
  	case FB_VISUAL_PSEUDOCOLOR:
  		ret = pxafb_setpalettereg(regno, red, green, blue, trans, info);
  		break;
  	}
  
  	return ret;
  }
878f57831   Eric Miao   [ARM] pxafb: clea...
233
234
  /* calculate pixel depth, transparency bit included, >=16bpp formats _only_ */
  static inline int var_to_depth(struct fb_var_screeninfo *var)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  {
878f57831   Eric Miao   [ARM] pxafb: clea...
236
237
238
239
240
241
242
243
  	return var->red.length + var->green.length +
  		var->blue.length + var->transp.length;
  }
  
  /* calculate 4-bit BPP value for LCCR3 and OVLxC1 */
  static int pxafb_var_to_bpp(struct fb_var_screeninfo *var)
  {
  	int bpp = -EINVAL;
b0086efba   eric miao   pxafb: fix variou...
244
  	switch (var->bits_per_pixel) {
878f57831   Eric Miao   [ARM] pxafb: clea...
245
246
247
248
249
  	case 1:  bpp = 0; break;
  	case 2:  bpp = 1; break;
  	case 4:  bpp = 2; break;
  	case 8:  bpp = 3; break;
  	case 16: bpp = 4; break;
c1450f156   Stefan Schmidt   [ARM] 5164/1: pxa...
250
  	case 24:
878f57831   Eric Miao   [ARM] pxafb: clea...
251
252
253
254
  		switch (var_to_depth(var)) {
  		case 18: bpp = 6; break; /* 18-bits/pixel packed */
  		case 19: bpp = 8; break; /* 19-bits/pixel packed */
  		case 24: bpp = 9; break;
c1450f156   Stefan Schmidt   [ARM] 5164/1: pxa...
255
256
257
  		}
  		break;
  	case 32:
878f57831   Eric Miao   [ARM] pxafb: clea...
258
259
260
261
  		switch (var_to_depth(var)) {
  		case 18: bpp = 5; break; /* 18-bits/pixel unpacked */
  		case 19: bpp = 7; break; /* 19-bits/pixel unpacked */
  		case 25: bpp = 10; break;
c1450f156   Stefan Schmidt   [ARM] 5164/1: pxa...
262
263
  		}
  		break;
b0086efba   eric miao   pxafb: fix variou...
264
  	}
878f57831   Eric Miao   [ARM] pxafb: clea...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  	return bpp;
  }
  
  /*
   *  pxafb_var_to_lccr3():
   *    Convert a bits per pixel value to the correct bit pattern for LCCR3
   *
   *  NOTE: for PXA27x with overlays support, the LCCR3_PDFOR_x bits have an
   *  implication of the acutal use of transparency bit,  which we handle it
   *  here separatedly. See PXA27x Developer's Manual, Section <<7.4.6 Pixel
   *  Formats>> for the valid combination of PDFOR, PAL_FOR for various BPP.
   *
   *  Transparency for palette pixel formats is not supported at the moment.
   */
  static uint32_t pxafb_var_to_lccr3(struct fb_var_screeninfo *var)
  {
  	int bpp = pxafb_var_to_bpp(var);
  	uint32_t lccr3;
  
  	if (bpp < 0)
  		return 0;
  
  	lccr3 = LCCR3_BPP(bpp);
  
  	switch (var_to_depth(var)) {
  	case 16: lccr3 |= var->transp.length ? LCCR3_PDFOR_3 : 0; break;
  	case 18: lccr3 |= LCCR3_PDFOR_3; break;
  	case 24: lccr3 |= var->transp.length ? LCCR3_PDFOR_2 : LCCR3_PDFOR_3;
  		 break;
  	case 19:
  	case 25: lccr3 |= LCCR3_PDFOR_0; break;
  	}
  	return lccr3;
  }
  
  #define SET_PIXFMT(v, r, g, b, t)				\
  ({								\
  	(v)->transp.offset = (t) ? (r) + (g) + (b) : 0;		\
  	(v)->transp.length = (t) ? (t) : 0;			\
  	(v)->blue.length   = (b); (v)->blue.offset = 0;		\
  	(v)->green.length  = (g); (v)->green.offset = (b);	\
  	(v)->red.length    = (r); (v)->red.offset = (b) + (g);	\
  })
  
  /* set the RGBT bitfields of fb_var_screeninf according to
   * var->bits_per_pixel and given depth
   */
  static void pxafb_set_pixfmt(struct fb_var_screeninfo *var, int depth)
  {
  	if (depth == 0)
  		depth = var->bits_per_pixel;
  
  	if (var->bits_per_pixel < 16) {
  		/* indexed pixel formats */
  		var->red.offset    = 0; var->red.length    = 8;
  		var->green.offset  = 0; var->green.length  = 8;
  		var->blue.offset   = 0; var->blue.length   = 8;
  		var->transp.offset = 0; var->transp.length = 8;
  	}
  
  	switch (depth) {
  	case 16: var->transp.length ?
  		 SET_PIXFMT(var, 5, 5, 5, 1) :		/* RGBT555 */
  		 SET_PIXFMT(var, 5, 6, 5, 0); break;	/* RGB565 */
  	case 18: SET_PIXFMT(var, 6, 6, 6, 0); break;	/* RGB666 */
  	case 19: SET_PIXFMT(var, 6, 6, 6, 1); break;	/* RGBT666 */
  	case 24: var->transp.length ?
  		 SET_PIXFMT(var, 8, 8, 7, 1) :		/* RGBT887 */
  		 SET_PIXFMT(var, 8, 8, 8, 0); break;	/* RGB888 */
  	case 25: SET_PIXFMT(var, 8, 8, 8, 1); break;	/* RGBT888 */
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
344
345
346
  }
  
  #ifdef CONFIG_CPU_FREQ
  /*
   *  pxafb_display_dma_period()
   *    Calculate the minimum period (in picoseconds) between two DMA
   *    requests for the LCD controller.  If we hit this, it means we're
   *    doing nothing but LCD DMA.
   */
  static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var)
  {
b0086efba   eric miao   pxafb: fix variou...
347
348
349
350
351
  	/*
  	 * Period = pixclock * bits_per_byte * bytes_per_transfer
  	 *              / memory_bits_per_pixel;
  	 */
  	return var->pixclock * 8 * 16 / var->bits_per_pixel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
  #endif
  
  /*
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
356
357
358
   * Select the smallest mode that allows the desired resolution to be
   * displayed. If desired parameters can be rounded up.
   */
b0086efba   eric miao   pxafb: fix variou...
359
360
  static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach,
  					     struct fb_var_screeninfo *var)
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
361
362
363
364
365
  {
  	struct pxafb_mode_info *mode = NULL;
  	struct pxafb_mode_info *modelist = mach->modes;
  	unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
  	unsigned int i;
b0086efba   eric miao   pxafb: fix variou...
366
367
368
369
370
371
  	for (i = 0; i < mach->num_modes; i++) {
  		if (modelist[i].xres >= var->xres &&
  		    modelist[i].yres >= var->yres &&
  		    modelist[i].xres < best_x &&
  		    modelist[i].yres < best_y &&
  		    modelist[i].bpp >= var->bits_per_pixel) {
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
372
373
374
375
376
377
378
379
  			best_x = modelist[i].xres;
  			best_y = modelist[i].yres;
  			mode = &modelist[i];
  		}
  	}
  
  	return mode;
  }
b0086efba   eric miao   pxafb: fix variou...
380
381
  static void pxafb_setmode(struct fb_var_screeninfo *var,
  			  struct pxafb_mode_info *mode)
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
382
383
384
385
386
387
388
389
390
391
392
393
394
  {
  	var->xres		= mode->xres;
  	var->yres		= mode->yres;
  	var->bits_per_pixel	= mode->bpp;
  	var->pixclock		= mode->pixclock;
  	var->hsync_len		= mode->hsync_len;
  	var->left_margin	= mode->left_margin;
  	var->right_margin	= mode->right_margin;
  	var->vsync_len		= mode->vsync_len;
  	var->upper_margin	= mode->upper_margin;
  	var->lower_margin	= mode->lower_margin;
  	var->sync		= mode->sync;
  	var->grayscale		= mode->cmap_greyscale;
049ad833b   Pieter Grimmerink   pxafb: add transp...
395
  	var->transp.length	= mode->transparency;
878f57831   Eric Miao   [ARM] pxafb: clea...
396
397
398
  
  	/* set the initial RGBA bitfields */
  	pxafb_set_pixfmt(var, mode->depth);
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
399
  }
3f16ff608   Eric Miao   [ARM] pxafb: clea...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  static int pxafb_adjust_timing(struct pxafb_info *fbi,
  			       struct fb_var_screeninfo *var)
  {
  	int line_length;
  
  	var->xres = max_t(int, var->xres, MIN_XRES);
  	var->yres = max_t(int, var->yres, MIN_YRES);
  
  	if (!(fbi->lccr0 & LCCR0_LCDT)) {
  		clamp_val(var->hsync_len, 1, 64);
  		clamp_val(var->vsync_len, 1, 64);
  		clamp_val(var->left_margin,  1, 255);
  		clamp_val(var->right_margin, 1, 255);
  		clamp_val(var->upper_margin, 1, 255);
  		clamp_val(var->lower_margin, 1, 255);
  	}
  
  	/* make sure each line is aligned on word boundary */
  	line_length = var->xres * var->bits_per_pixel / 8;
  	line_length = ALIGN(line_length, 4);
  	var->xres = line_length * 8 / var->bits_per_pixel;
  
  	/* we don't support xpan, force xres_virtual to be equal to xres */
  	var->xres_virtual = var->xres;
  
  	if (var->accel_flags & FB_ACCELF_TEXT)
  		var->yres_virtual = fbi->fb.fix.smem_len / line_length;
  	else
  		var->yres_virtual = max(var->yres_virtual, var->yres);
  
  	/* check for limits */
  	if (var->xres > MAX_XRES || var->yres > MAX_YRES)
  		return -EINVAL;
  
  	if (var->yres > var->yres_virtual)
  		return -EINVAL;
  
  	return 0;
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
438
439
440
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
446
447
448
449
450
451
   *  pxafb_check_var():
   *    Get the video params out of 'var'. If a value doesn't fit, round it up,
   *    if it's too big, return -EINVAL.
   *
   *    Round up in the following order: bits_per_pixel, xres,
   *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
   *    bitfields, horizontal timing, vertical timing.
   */
  static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  {
  	struct pxafb_info *fbi = (struct pxafb_info *)info;
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
452
  	struct pxafb_mach_info *inf = fbi->dev->platform_data;
878f57831   Eric Miao   [ARM] pxafb: clea...
453
  	int err;
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
454
455
456
457
458
459
460
461
  
  	if (inf->fixed_modes) {
  		struct pxafb_mode_info *mode;
  
  		mode = pxafb_getmode(inf, var);
  		if (!mode)
  			return -EINVAL;
  		pxafb_setmode(var, mode);
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
462
  	}
878f57831   Eric Miao   [ARM] pxafb: clea...
463
464
465
466
  	/* do a test conversion to BPP fields to check the color formats */
  	err = pxafb_var_to_bpp(var);
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467

878f57831   Eric Miao   [ARM] pxafb: clea...
468
  	pxafb_set_pixfmt(var, var_to_depth(var));
c1450f156   Stefan Schmidt   [ARM] 5164/1: pxa...
469

3f16ff608   Eric Miao   [ARM] pxafb: clea...
470
471
472
  	err = pxafb_adjust_timing(fbi, var);
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
  
  #ifdef CONFIG_CPU_FREQ
78d3cfd33   Russell King   [ARM] pxa: fix px...
475
476
477
  	pr_debug("pxafb: dma period = %d ps
  ",
  		 pxafb_display_dma_period(var));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
481
  #endif
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
487
488
489
  /*
   * pxafb_set_par():
   *	Set the user defined part of the display for the specified console
   */
  static int pxafb_set_par(struct fb_info *info)
  {
  	struct pxafb_info *fbi = (struct pxafb_info *)info;
  	struct fb_var_screeninfo *var = &info->var;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490

c1450f156   Stefan Schmidt   [ARM] 5164/1: pxa...
491
  	if (var->bits_per_pixel >= 16)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  		fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
  	else if (!fbi->cmap_static)
  		fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
  	else {
  		/*
  		 * Some people have weird ideas about wanting static
  		 * pseudocolor maps.  I suspect their user space
  		 * applications are broken.
  		 */
  		fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
  	}
  
  	fbi->fb.fix.line_length = var->xres_virtual *
  				  var->bits_per_pixel / 8;
c1450f156   Stefan Schmidt   [ARM] 5164/1: pxa...
506
  	if (var->bits_per_pixel >= 16)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
  		fbi->palette_size = 0;
  	else
b0086efba   eric miao   pxafb: fix variou...
509
510
  		fbi->palette_size = var->bits_per_pixel == 1 ?
  					4 : 1 << var->bits_per_pixel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511

2c42dd8eb   eric miao   pxafb: introduce ...
512
  	fbi->palette_cpu = (u16 *)&fbi->dma_buff->palette[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513

c1450f156   Stefan Schmidt   [ARM] 5164/1: pxa...
514
  	if (fbi->fb.var.bits_per_pixel >= 16)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
520
521
522
  		fb_dealloc_cmap(&fbi->fb.cmap);
  	else
  		fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
  
  	pxafb_activate_var(var, fbi);
  
  	return 0;
  }
6e354846e   Eric Miao   [ARM] pxafb: add ...
523
524
525
526
  static int pxafb_pan_display(struct fb_var_screeninfo *var,
  			     struct fb_info *info)
  {
  	struct pxafb_info *fbi = (struct pxafb_info *)info;
448ac4797   Sven Neumann   pxafb: use passed...
527
  	struct fb_var_screeninfo newvar;
6e354846e   Eric Miao   [ARM] pxafb: add ...
528
529
530
531
  	int dma = DMA_MAX + DMA_BASE;
  
  	if (fbi->state != C_ENABLE)
  		return 0;
448ac4797   Sven Neumann   pxafb: use passed...
532
533
534
535
536
537
538
539
540
541
  	/* Only take .xoffset, .yoffset and .vmode & FB_VMODE_YWRAP from what
  	 * was passed in and copy the rest from the old screeninfo.
  	 */
  	memcpy(&newvar, &fbi->fb.var, sizeof(newvar));
  	newvar.xoffset = var->xoffset;
  	newvar.yoffset = var->yoffset;
  	newvar.vmode &= ~FB_VMODE_YWRAP;
  	newvar.vmode |= var->vmode & FB_VMODE_YWRAP;
  
  	setup_base_frame(fbi, &newvar, 1);
6e354846e   Eric Miao   [ARM] pxafb: add ...
542
543
544
545
546
547
548
  
  	if (fbi->lccr0 & LCCR0_SDS)
  		lcd_writel(fbi, FBR1, fbi->fdadr[dma + 1] | 0x1);
  
  	lcd_writel(fbi, FBR0, fbi->fdadr[dma] | 0x1);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
555
556
557
558
   * pxafb_blank():
   *	Blank the display by setting all palette values to zero.  Note, the
   * 	16 bpp mode does not really use the palette, so this will not
   *      blank the display in all modes.
   */
  static int pxafb_blank(int blank, struct fb_info *info)
  {
  	struct pxafb_info *fbi = (struct pxafb_info *)info;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
564
565
566
567
568
569
  	switch (blank) {
  	case FB_BLANK_POWERDOWN:
  	case FB_BLANK_VSYNC_SUSPEND:
  	case FB_BLANK_HSYNC_SUSPEND:
  	case FB_BLANK_NORMAL:
  		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
  		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
  			for (i = 0; i < fbi->palette_size; i++)
  				pxafb_setpalettereg(i, 0, 0, 0, 0, info);
  
  		pxafb_schedule_work(fbi, C_DISABLE);
b0086efba   eric miao   pxafb: fix variou...
570
  		/* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
  		break;
  
  	case FB_BLANK_UNBLANK:
b0086efba   eric miao   pxafb: fix variou...
574
  		/* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
  		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
  		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
  			fb_set_cmap(&fbi->fb.cmap, info);
  		pxafb_schedule_work(fbi, C_ENABLE);
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
  static struct fb_ops pxafb_ops = {
  	.owner		= THIS_MODULE,
  	.fb_check_var	= pxafb_check_var,
  	.fb_set_par	= pxafb_set_par,
6e354846e   Eric Miao   [ARM] pxafb: add ...
586
  	.fb_pan_display	= pxafb_pan_display,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
590
591
  	.fb_setcolreg	= pxafb_setcolreg,
  	.fb_fillrect	= cfb_fillrect,
  	.fb_copyarea	= cfb_copyarea,
  	.fb_imageblit	= cfb_imageblit,
  	.fb_blank	= pxafb_blank,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  };
198fc108e   Eric Miao   [ARM] pxafb: add ...
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
  #ifdef CONFIG_FB_PXA_OVERLAY
  static void overlay1fb_setup(struct pxafb_layer *ofb)
  {
  	int size = ofb->fb.fix.line_length * ofb->fb.var.yres_virtual;
  	unsigned long start = ofb->video_mem_phys;
  	setup_frame_dma(ofb->fbi, DMA_OV1, PAL_NONE, start, size);
  }
  
  /* Depending on the enable status of overlay1/2, the DMA should be
   * updated from FDADRx (when disabled) or FBRx (when enabled).
   */
  static void overlay1fb_enable(struct pxafb_layer *ofb)
  {
  	int enabled = lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN;
  	uint32_t fdadr1 = ofb->fbi->fdadr[DMA_OV1] | (enabled ? 0x1 : 0);
  
  	lcd_writel(ofb->fbi, enabled ? FBR1 : FDADR1, fdadr1);
  	lcd_writel(ofb->fbi, OVL1C2, ofb->control[1]);
  	lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] | OVLxC1_OEN);
  }
  
  static void overlay1fb_disable(struct pxafb_layer *ofb)
  {
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
616
617
618
619
620
621
  	uint32_t lccr5;
  
  	if (!(lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN))
  		return;
  
  	lccr5 = lcd_readl(ofb->fbi, LCCR5);
198fc108e   Eric Miao   [ARM] pxafb: add ...
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  
  	lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] & ~OVLxC1_OEN);
  
  	lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(1));
  	lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(1));
  	lcd_writel(ofb->fbi, FBR1, ofb->fbi->fdadr[DMA_OV1] | 0x3);
  
  	if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) == 0)
  		pr_warning("%s: timeout disabling overlay1
  ", __func__);
  
  	lcd_writel(ofb->fbi, LCCR5, lccr5);
  }
  
  static void overlay2fb_setup(struct pxafb_layer *ofb)
  {
  	int size, div = 1, pfor = NONSTD_TO_PFOR(ofb->fb.var.nonstd);
  	unsigned long start[3] = { ofb->video_mem_phys, 0, 0 };
  
  	if (pfor == OVERLAY_FORMAT_RGB || pfor == OVERLAY_FORMAT_YUV444_PACKED) {
  		size = ofb->fb.fix.line_length * ofb->fb.var.yres_virtual;
  		setup_frame_dma(ofb->fbi, DMA_OV2_Y, -1, start[0], size);
  	} else {
  		size = ofb->fb.var.xres_virtual * ofb->fb.var.yres_virtual;
  		switch (pfor) {
  		case OVERLAY_FORMAT_YUV444_PLANAR: div = 1; break;
  		case OVERLAY_FORMAT_YUV422_PLANAR: div = 2; break;
  		case OVERLAY_FORMAT_YUV420_PLANAR: div = 4; break;
  		}
  		start[1] = start[0] + size;
  		start[2] = start[1] + size / div;
  		setup_frame_dma(ofb->fbi, DMA_OV2_Y,  -1, start[0], size);
  		setup_frame_dma(ofb->fbi, DMA_OV2_Cb, -1, start[1], size / div);
  		setup_frame_dma(ofb->fbi, DMA_OV2_Cr, -1, start[2], size / div);
  	}
  }
  
  static void overlay2fb_enable(struct pxafb_layer *ofb)
  {
  	int pfor = NONSTD_TO_PFOR(ofb->fb.var.nonstd);
  	int enabled = lcd_readl(ofb->fbi, OVL2C1) & OVLxC1_OEN;
  	uint32_t fdadr2 = ofb->fbi->fdadr[DMA_OV2_Y]  | (enabled ? 0x1 : 0);
  	uint32_t fdadr3 = ofb->fbi->fdadr[DMA_OV2_Cb] | (enabled ? 0x1 : 0);
  	uint32_t fdadr4 = ofb->fbi->fdadr[DMA_OV2_Cr] | (enabled ? 0x1 : 0);
  
  	if (pfor == OVERLAY_FORMAT_RGB || pfor == OVERLAY_FORMAT_YUV444_PACKED)
  		lcd_writel(ofb->fbi, enabled ? FBR2 : FDADR2, fdadr2);
  	else {
  		lcd_writel(ofb->fbi, enabled ? FBR2 : FDADR2, fdadr2);
  		lcd_writel(ofb->fbi, enabled ? FBR3 : FDADR3, fdadr3);
  		lcd_writel(ofb->fbi, enabled ? FBR4 : FDADR4, fdadr4);
  	}
  	lcd_writel(ofb->fbi, OVL2C2, ofb->control[1]);
  	lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] | OVLxC1_OEN);
  }
  
  static void overlay2fb_disable(struct pxafb_layer *ofb)
  {
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
680
681
682
683
684
685
  	uint32_t lccr5;
  
  	if (!(lcd_readl(ofb->fbi, OVL2C1) & OVLxC1_OEN))
  		return;
  
  	lccr5 = lcd_readl(ofb->fbi, LCCR5);
198fc108e   Eric Miao   [ARM] pxafb: add ...
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
  
  	lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] & ~OVLxC1_OEN);
  
  	lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(2));
  	lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(2));
  	lcd_writel(ofb->fbi, FBR2, ofb->fbi->fdadr[DMA_OV2_Y]  | 0x3);
  	lcd_writel(ofb->fbi, FBR3, ofb->fbi->fdadr[DMA_OV2_Cb] | 0x3);
  	lcd_writel(ofb->fbi, FBR4, ofb->fbi->fdadr[DMA_OV2_Cr] | 0x3);
  
  	if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) == 0)
  		pr_warning("%s: timeout disabling overlay2
  ", __func__);
  }
  
  static struct pxafb_layer_ops ofb_ops[] = {
  	[0] = {
  		.enable		= overlay1fb_enable,
  		.disable	= overlay1fb_disable,
  		.setup		= overlay1fb_setup,
  	},
  	[1] = {
  		.enable		= overlay2fb_enable,
  		.disable	= overlay2fb_disable,
  		.setup		= overlay2fb_setup,
  	},
  };
  
  static int overlayfb_open(struct fb_info *info, int user)
  {
  	struct pxafb_layer *ofb = (struct pxafb_layer *)info;
  
  	/* no support for framebuffer console on overlay */
  	if (user == 0)
  		return -ENODEV;
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
720
721
722
  	if (ofb->usage++ == 0)
  		/* unblank the base framebuffer */
  		fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
198fc108e   Eric Miao   [ARM] pxafb: add ...
723

198fc108e   Eric Miao   [ARM] pxafb: add ...
724
725
726
727
728
729
  	return 0;
  }
  
  static int overlayfb_release(struct fb_info *info, int user)
  {
  	struct pxafb_layer *ofb = (struct pxafb_layer*) info;
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
730
731
732
733
734
735
  	if (ofb->usage == 1) {
  		ofb->ops->disable(ofb);
  		ofb->fb.var.height	= -1;
  		ofb->fb.var.width	= -1;
  		ofb->fb.var.xres = ofb->fb.var.xres_virtual = 0;
  		ofb->fb.var.yres = ofb->fb.var.yres_virtual = 0;
198fc108e   Eric Miao   [ARM] pxafb: add ...
736

1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
737
738
  		ofb->usage--;
  	}
198fc108e   Eric Miao   [ARM] pxafb: add ...
739
740
741
742
743
744
745
746
747
748
749
  	return 0;
  }
  
  static int overlayfb_check_var(struct fb_var_screeninfo *var,
  			       struct fb_info *info)
  {
  	struct pxafb_layer *ofb = (struct pxafb_layer *)info;
  	struct fb_var_screeninfo *base_var = &ofb->fbi->fb.var;
  	int xpos, ypos, pfor, bpp;
  
  	xpos = NONSTD_TO_XPOS(var->nonstd);
dcf8eee94   Vasily Khoruzhick   ARM: pxafb: fix t...
750
  	ypos = NONSTD_TO_YPOS(var->nonstd);
198fc108e   Eric Miao   [ARM] pxafb: add ...
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
  	pfor = NONSTD_TO_PFOR(var->nonstd);
  
  	bpp = pxafb_var_to_bpp(var);
  	if (bpp < 0)
  		return -EINVAL;
  
  	/* no support for YUV format on overlay1 */
  	if (ofb->id == OVERLAY1 && pfor != 0)
  		return -EINVAL;
  
  	/* for YUV packed formats, bpp = 'minimum bpp of YUV components' */
  	switch (pfor) {
  	case OVERLAY_FORMAT_RGB:
  		bpp = pxafb_var_to_bpp(var);
  		if (bpp < 0)
  			return -EINVAL;
  
  		pxafb_set_pixfmt(var, var_to_depth(var));
  		break;
  	case OVERLAY_FORMAT_YUV444_PACKED: bpp = 24; break;
  	case OVERLAY_FORMAT_YUV444_PLANAR: bpp = 8; break;
  	case OVERLAY_FORMAT_YUV422_PLANAR: bpp = 4; break;
  	case OVERLAY_FORMAT_YUV420_PLANAR: bpp = 2; break;
  	default:
  		return -EINVAL;
  	}
  
  	/* each line must start at a 32-bit word boundary */
  	if ((xpos * bpp) % 32)
  		return -EINVAL;
  
  	/* xres must align on 32-bit word boundary */
  	var->xres = roundup(var->xres * bpp, 32) / bpp;
  
  	if ((xpos + var->xres > base_var->xres) ||
  	    (ypos + var->yres > base_var->yres))
  		return -EINVAL;
  
  	var->xres_virtual = var->xres;
  	var->yres_virtual = max(var->yres, var->yres_virtual);
  	return 0;
  }
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
793
  static int overlayfb_check_video_memory(struct pxafb_layer *ofb)
198fc108e   Eric Miao   [ARM] pxafb: add ...
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  {
  	struct fb_var_screeninfo *var = &ofb->fb.var;
  	int pfor = NONSTD_TO_PFOR(var->nonstd);
  	int size, bpp = 0;
  
  	switch (pfor) {
  	case OVERLAY_FORMAT_RGB: bpp = var->bits_per_pixel; break;
  	case OVERLAY_FORMAT_YUV444_PACKED: bpp = 24; break;
  	case OVERLAY_FORMAT_YUV444_PLANAR: bpp = 24; break;
  	case OVERLAY_FORMAT_YUV422_PLANAR: bpp = 16; break;
  	case OVERLAY_FORMAT_YUV420_PLANAR: bpp = 12; break;
  	}
  
  	ofb->fb.fix.line_length = var->xres_virtual * bpp / 8;
  
  	size = PAGE_ALIGN(ofb->fb.fix.line_length * var->yres_virtual);
198fc108e   Eric Miao   [ARM] pxafb: add ...
810
811
812
  	if (ofb->video_mem) {
  		if (ofb->video_mem_size >= size)
  			return 0;
198fc108e   Eric Miao   [ARM] pxafb: add ...
813
  	}
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
814
  	return -EINVAL;
198fc108e   Eric Miao   [ARM] pxafb: add ...
815
816
817
818
819
820
821
  }
  
  static int overlayfb_set_par(struct fb_info *info)
  {
  	struct pxafb_layer *ofb = (struct pxafb_layer *)info;
  	struct fb_var_screeninfo *var = &info->var;
  	int xpos, ypos, pfor, bpp, ret;
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
822
  	ret = overlayfb_check_video_memory(ofb);
198fc108e   Eric Miao   [ARM] pxafb: add ...
823
824
825
826
827
  	if (ret)
  		return ret;
  
  	bpp  = pxafb_var_to_bpp(var);
  	xpos = NONSTD_TO_XPOS(var->nonstd);
dcf8eee94   Vasily Khoruzhick   ARM: pxafb: fix t...
828
  	ypos = NONSTD_TO_YPOS(var->nonstd);
198fc108e   Eric Miao   [ARM] pxafb: add ...
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
  	pfor = NONSTD_TO_PFOR(var->nonstd);
  
  	ofb->control[0] = OVLxC1_PPL(var->xres) | OVLxC1_LPO(var->yres) |
  			  OVLxC1_BPP(bpp);
  	ofb->control[1] = OVLxC2_XPOS(xpos) | OVLxC2_YPOS(ypos);
  
  	if (ofb->id == OVERLAY2)
  		ofb->control[1] |= OVL2C2_PFOR(pfor);
  
  	ofb->ops->setup(ofb);
  	ofb->ops->enable(ofb);
  	return 0;
  }
  
  static struct fb_ops overlay_fb_ops = {
  	.owner			= THIS_MODULE,
  	.fb_open		= overlayfb_open,
  	.fb_release		= overlayfb_release,
  	.fb_check_var 		= overlayfb_check_var,
  	.fb_set_par		= overlayfb_set_par,
  };
  
  static void __devinit init_pxafb_overlay(struct pxafb_info *fbi,
  					 struct pxafb_layer *ofb, int id)
  {
  	sprintf(ofb->fb.fix.id, "overlay%d", id + 1);
  
  	ofb->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
  	ofb->fb.fix.xpanstep		= 0;
  	ofb->fb.fix.ypanstep		= 1;
  
  	ofb->fb.var.activate		= FB_ACTIVATE_NOW;
  	ofb->fb.var.height		= -1;
  	ofb->fb.var.width		= -1;
  	ofb->fb.var.vmode		= FB_VMODE_NONINTERLACED;
  
  	ofb->fb.fbops			= &overlay_fb_ops;
  	ofb->fb.flags			= FBINFO_FLAG_DEFAULT;
  	ofb->fb.node			= -1;
  	ofb->fb.pseudo_palette		= NULL;
  
  	ofb->id = id;
  	ofb->ops = &ofb_ops[id];
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
872
  	ofb->usage = 0;
198fc108e   Eric Miao   [ARM] pxafb: add ...
873
874
875
  	ofb->fbi = fbi;
  	init_completion(&ofb->branch_done);
  }
782385ae1   Eric Miao   [ARM] pxa: fix ov...
876
877
878
879
880
881
882
  static inline int pxafb_overlay_supported(void)
  {
  	if (cpu_is_pxa27x() || cpu_is_pxa3xx())
  		return 1;
  
  	return 0;
  }
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
  static int __devinit pxafb_overlay_map_video_memory(struct pxafb_info *pxafb,
  	struct pxafb_layer *ofb)
  {
  	/* We assume that user will use at most video_mem_size for overlay fb,
  	 * anyway, it's useless to use 16bpp main plane and 24bpp overlay
  	 */
  	ofb->video_mem = alloc_pages_exact(PAGE_ALIGN(pxafb->video_mem_size),
  		GFP_KERNEL | __GFP_ZERO);
  	if (ofb->video_mem == NULL)
  		return -ENOMEM;
  
  	ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
  	ofb->video_mem_size = PAGE_ALIGN(pxafb->video_mem_size);
  
  	mutex_lock(&ofb->fb.mm_lock);
  	ofb->fb.fix.smem_start	= ofb->video_mem_phys;
  	ofb->fb.fix.smem_len	= pxafb->video_mem_size;
  	mutex_unlock(&ofb->fb.mm_lock);
  
  	ofb->fb.screen_base	= ofb->video_mem;
  
  	return 0;
  }
  
  static void __devinit pxafb_overlay_init(struct pxafb_info *fbi)
198fc108e   Eric Miao   [ARM] pxafb: add ...
908
909
  {
  	int i, ret;
782385ae1   Eric Miao   [ARM] pxa: fix ov...
910
  	if (!pxafb_overlay_supported())
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
911
  		return;
782385ae1   Eric Miao   [ARM] pxa: fix ov...
912

198fc108e   Eric Miao   [ARM] pxafb: add ...
913
  	for (i = 0; i < 2; i++) {
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
914
915
916
  		struct pxafb_layer *ofb = &fbi->overlay[i];
  		init_pxafb_overlay(fbi, ofb, i);
  		ret = register_framebuffer(&ofb->fb);
198fc108e   Eric Miao   [ARM] pxafb: add ...
917
918
919
  		if (ret) {
  			dev_err(fbi->dev, "failed to register overlay %d
  ", i);
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
920
921
922
923
924
925
926
927
928
929
  			continue;
  		}
  		ret = pxafb_overlay_map_video_memory(fbi, ofb);
  		if (ret) {
  			dev_err(fbi->dev,
  				"failed to map video memory for overlay %d
  ",
  				i);
  			unregister_framebuffer(&ofb->fb);
  			continue;
198fc108e   Eric Miao   [ARM] pxafb: add ...
930
  		}
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
931
  		ofb->registered = 1;
198fc108e   Eric Miao   [ARM] pxafb: add ...
932
933
934
935
  	}
  
  	/* mask all IU/BS/EOF/SOF interrupts */
  	lcd_writel(fbi, LCCR5, ~0);
198fc108e   Eric Miao   [ARM] pxafb: add ...
936
937
  	pr_info("PXA Overlay driver loaded successfully!
  ");
198fc108e   Eric Miao   [ARM] pxafb: add ...
938
939
940
941
942
  }
  
  static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi)
  {
  	int i;
782385ae1   Eric Miao   [ARM] pxa: fix ov...
943
944
  	if (!pxafb_overlay_supported())
  		return;
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
945
946
947
948
949
950
951
952
953
  	for (i = 0; i < 2; i++) {
  		struct pxafb_layer *ofb = &fbi->overlay[i];
  		if (ofb->registered) {
  			if (ofb->video_mem)
  				free_pages_exact(ofb->video_mem,
  					ofb->video_mem_size);
  			unregister_framebuffer(&ofb->fb);
  		}
  	}
198fc108e   Eric Miao   [ARM] pxafb: add ...
954
955
956
957
958
  }
  #else
  static inline void pxafb_overlay_init(struct pxafb_info *fbi) {}
  static inline void pxafb_overlay_exit(struct pxafb_info *fbi) {}
  #endif /* CONFIG_FB_PXA_OVERLAY */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
  /*
   * Calculate the PCD value from the clock rate (in picoseconds).
   * We take account of the PPCR clock setting.
   * From PXA Developer's Manual:
   *
   *   PixelClock =      LCLK
   *                -------------
   *                2 ( PCD + 1 )
   *
   *   PCD =      LCLK
   *         ------------- - 1
   *         2(PixelClock)
   *
   * Where:
   *   LCLK = LCD/Memory Clock
   *   PCD = LCCR3[7:0]
   *
   * PixelClock here is in Hz while the pixclock argument given is the
   * period in picoseconds. Hence PixelClock = 1 / ( pixclock * 10^-12 )
   *
   * The function get_lclk_frequency_10khz returns LCLK in units of
   * 10khz. Calling the result of this function lclk gives us the
   * following
   *
   *    PCD = (lclk * 10^4 ) * ( pixclock * 10^-12 )
   *          -------------------------------------- - 1
   *                          2
   *
   * Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
   */
b0086efba   eric miao   pxafb: fix variou...
989
990
  static inline unsigned int get_pcd(struct pxafb_info *fbi,
  				   unsigned int pixclock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
994
  {
  	unsigned long long pcd;
  
  	/* FIXME: Need to take into account Double Pixel Clock mode
72e3524c0   Russell King   [ARM] pxa: update...
995
996
997
998
  	 * (DPC) bit? or perhaps set it based on the various clock
  	 * speeds */
  	pcd = (unsigned long long)(clk_get_rate(fbi->clk) / 10000);
  	pcd *= pixclock;
bf1b8ab6f   Nicolas Pitre   [PATCH] ARM: 2721...
999
  	do_div(pcd, 100000000 * 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
1002
1003
1004
1005
  	/* no need for this, since we should subtract 1 anyway. they cancel */
  	/* pcd += 1; */ /* make up for integer math truncations */
  	return (unsigned int)pcd;
  }
  
  /*
ba44cd2d8   Richard Purdie   [PATCH] pxafb: Ad...
1006
   * Some touchscreens need hsync information from the video driver to
72e3524c0   Russell King   [ARM] pxa: update...
1007
1008
1009
   * function correctly. We export it here.  Note that 'hsync_time' and
   * the value returned from pxafb_get_hsync_time() is the *reciprocal*
   * of the hsync period in seconds.
ba44cd2d8   Richard Purdie   [PATCH] pxafb: Ad...
1010
1011
1012
   */
  static inline void set_hsync_time(struct pxafb_info *fbi, unsigned int pcd)
  {
72e3524c0   Russell King   [ARM] pxa: update...
1013
  	unsigned long htime;
ba44cd2d8   Richard Purdie   [PATCH] pxafb: Ad...
1014
1015
  
  	if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) {
b0086efba   eric miao   pxafb: fix variou...
1016
  		fbi->hsync_time = 0;
ba44cd2d8   Richard Purdie   [PATCH] pxafb: Ad...
1017
1018
  		return;
  	}
72e3524c0   Russell King   [ARM] pxa: update...
1019
  	htime = clk_get_rate(fbi->clk) / (pcd * fbi->fb.var.hsync_len);
ba44cd2d8   Richard Purdie   [PATCH] pxafb: Ad...
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
  	fbi->hsync_time = htime;
  }
  
  unsigned long pxafb_get_hsync_time(struct device *dev)
  {
  	struct pxafb_info *fbi = dev_get_drvdata(dev);
  
  	/* If display is blanked/suspended, hsync isn't active */
  	if (!fbi || (fbi->state != C_ENABLE))
  		return 0;
  
  	return fbi->hsync_time;
  }
  EXPORT_SYMBOL(pxafb_get_hsync_time);
2c42dd8eb   eric miao   pxafb: introduce ...
1034
  static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
198fc108e   Eric Miao   [ARM] pxafb: add ...
1035
  			   unsigned long start, size_t size)
2c42dd8eb   eric miao   pxafb: introduce ...
1036
1037
1038
  {
  	struct pxafb_dma_descriptor *dma_desc, *pal_desc;
  	unsigned int dma_desc_off, pal_desc_off;
6e354846e   Eric Miao   [ARM] pxafb: add ...
1039
  	if (dma < 0 || dma >= DMA_MAX * 2)
2c42dd8eb   eric miao   pxafb: introduce ...
1040
1041
1042
1043
  		return -EINVAL;
  
  	dma_desc = &fbi->dma_buff->dma_desc[dma];
  	dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]);
198fc108e   Eric Miao   [ARM] pxafb: add ...
1044
  	dma_desc->fsadr = start;
2c42dd8eb   eric miao   pxafb: introduce ...
1045
1046
  	dma_desc->fidr  = 0;
  	dma_desc->ldcmd = size;
6e354846e   Eric Miao   [ARM] pxafb: add ...
1047
  	if (pal < 0 || pal >= PAL_MAX * 2) {
2c42dd8eb   eric miao   pxafb: introduce ...
1048
1049
1050
  		dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
  		fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
  	} else {
62cfcf4f4   Jürgen Schindele   [ARM] 5090/1: Cor...
1051
1052
  		pal_desc = &fbi->dma_buff->pal_desc[pal];
  		pal_desc_off = offsetof(struct pxafb_dma_buff, pal_desc[pal]);
2c42dd8eb   eric miao   pxafb: introduce ...
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  
  		pal_desc->fsadr = fbi->dma_buff_phys + pal * PALETTE_SIZE;
  		pal_desc->fidr  = 0;
  
  		if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
  			pal_desc->ldcmd = fbi->palette_size * sizeof(u16);
  		else
  			pal_desc->ldcmd = fbi->palette_size * sizeof(u32);
  
  		pal_desc->ldcmd |= LDCMD_PAL;
  
  		/* flip back and forth between palette and frame buffer */
  		pal_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
  		dma_desc->fdadr = fbi->dma_buff_phys + pal_desc_off;
  		fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
  	}
  
  	return 0;
  }
448ac4797   Sven Neumann   pxafb: use passed...
1072
1073
1074
  static void setup_base_frame(struct pxafb_info *fbi,
                               struct fb_var_screeninfo *var,
                               int branch)
6e354846e   Eric Miao   [ARM] pxafb: add ...
1075
  {
6e354846e   Eric Miao   [ARM] pxafb: add ...
1076
  	struct fb_fix_screeninfo *fix = &fbi->fb.fix;
198fc108e   Eric Miao   [ARM] pxafb: add ...
1077
1078
  	int nbytes, dma, pal, bpp = var->bits_per_pixel;
  	unsigned long offset;
6e354846e   Eric Miao   [ARM] pxafb: add ...
1079
1080
1081
1082
1083
  
  	dma = DMA_BASE + (branch ? DMA_MAX : 0);
  	pal = (bpp >= 16) ? PAL_NONE : PAL_BASE + (branch ? PAL_MAX : 0);
  
  	nbytes = fix->line_length * var->yres;
198fc108e   Eric Miao   [ARM] pxafb: add ...
1084
  	offset = fix->line_length * var->yoffset + fbi->video_mem_phys;
6e354846e   Eric Miao   [ARM] pxafb: add ...
1085
1086
1087
1088
1089
1090
1091
1092
  
  	if (fbi->lccr0 & LCCR0_SDS) {
  		nbytes = nbytes / 2;
  		setup_frame_dma(fbi, dma + 1, PAL_NONE, offset + nbytes, nbytes);
  	}
  
  	setup_frame_dma(fbi, dma, pal, offset, nbytes);
  }
3c42a4491   Eric Miao   pxafb: preliminar...
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
  #ifdef CONFIG_FB_PXA_SMARTPANEL
  static int setup_smart_dma(struct pxafb_info *fbi)
  {
  	struct pxafb_dma_descriptor *dma_desc;
  	unsigned long dma_desc_off, cmd_buff_off;
  
  	dma_desc = &fbi->dma_buff->dma_desc[DMA_CMD];
  	dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[DMA_CMD]);
  	cmd_buff_off = offsetof(struct pxafb_dma_buff, cmd_buff);
  
  	dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
  	dma_desc->fsadr = fbi->dma_buff_phys + cmd_buff_off;
  	dma_desc->fidr  = 0;
  	dma_desc->ldcmd = fbi->n_smart_cmds * sizeof(uint16_t);
  
  	fbi->fdadr[DMA_CMD] = dma_desc->fdadr;
  	return 0;
  }
  
  int pxafb_smart_flush(struct fb_info *info)
  {
  	struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
  	uint32_t prsr;
  	int ret = 0;
  
  	/* disable controller until all registers are set up */
  	lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
  
  	/* 1. make it an even number of commands to align on 32-bit boundary
  	 * 2. add the interrupt command to the end of the chain so we can
  	 *    keep track of the end of the transfer
  	 */
  
  	while (fbi->n_smart_cmds & 1)
  		fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_NOOP;
  
  	fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_INTERRUPT;
  	fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_WAIT_FOR_VSYNC;
  	setup_smart_dma(fbi);
  
  	/* continue to execute next command */
  	prsr = lcd_readl(fbi, PRSR) | PRSR_ST_OK | PRSR_CON_NT;
  	lcd_writel(fbi, PRSR, prsr);
  
  	/* stop the processor in case it executed "wait for sync" cmd */
  	lcd_writel(fbi, CMDCR, 0x0001);
  
  	/* don't send interrupts for fifo underruns on channel 6 */
  	lcd_writel(fbi, LCCR5, LCCR5_IUM(6));
  
  	lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
  	lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
  	lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
a0427509a   Eric Miao   [ARM] pxafb: add ...
1146
  	lcd_writel(fbi, LCCR4, fbi->reg_lccr4);
3c42a4491   Eric Miao   pxafb: preliminar...
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  	lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
  	lcd_writel(fbi, FDADR6, fbi->fdadr[6]);
  
  	/* begin sending */
  	lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
  
  	if (wait_for_completion_timeout(&fbi->command_done, HZ/2) == 0) {
  		pr_warning("%s: timeout waiting for command done
  ",
  				__func__);
  		ret = -ETIMEDOUT;
  	}
  
  	/* quick disable */
  	prsr = lcd_readl(fbi, PRSR) & ~(PRSR_ST_OK | PRSR_CON_NT);
  	lcd_writel(fbi, PRSR, prsr);
  	lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
  	lcd_writel(fbi, FDADR6, 0);
  	fbi->n_smart_cmds = 0;
  	return ret;
  }
  
  int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds)
  {
  	int i;
  	struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
69bdea704   Eric Miao   [ARM] pxafb: allo...
1173
1174
1175
1176
1177
1178
1179
1180
1181
  	for (i = 0; i < n_cmds; i++, cmds++) {
  		/* if it is a software delay, flush and delay */
  		if ((*cmds & 0xff00) == SMART_CMD_DELAY) {
  			pxafb_smart_flush(info);
  			mdelay(*cmds & 0xff);
  			continue;
  		}
  
  		/* leave 2 commands for INTERRUPT and WAIT_FOR_SYNC */
3c42a4491   Eric Miao   pxafb: preliminar...
1182
1183
  		if (fbi->n_smart_cmds == CMD_BUFF_SIZE - 8)
  			pxafb_smart_flush(info);
69bdea704   Eric Miao   [ARM] pxafb: allo...
1184
  		fbi->smart_cmds[fbi->n_smart_cmds++] = *cmds;
3c42a4491   Eric Miao   pxafb: preliminar...
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
  	}
  
  	return 0;
  }
  
  static unsigned int __smart_timing(unsigned time_ns, unsigned long lcd_clk)
  {
  	unsigned int t = (time_ns * (lcd_clk / 1000000) / 1000);
  	return (t == 0) ? 1 : t;
  }
  
  static void setup_smart_timing(struct pxafb_info *fbi,
  				struct fb_var_screeninfo *var)
  {
  	struct pxafb_mach_info *inf = fbi->dev->platform_data;
  	struct pxafb_mode_info *mode = &inf->modes[0];
  	unsigned long lclk = clk_get_rate(fbi->clk);
  	unsigned t1, t2, t3, t4;
  
  	t1 = max(mode->a0csrd_set_hld, mode->a0cswr_set_hld);
  	t2 = max(mode->rd_pulse_width, mode->wr_pulse_width);
  	t3 = mode->op_hold_time;
  	t4 = mode->cmd_inh_time;
  
  	fbi->reg_lccr1 =
  		LCCR1_DisWdth(var->xres) |
  		LCCR1_BegLnDel(__smart_timing(t1, lclk)) |
  		LCCR1_EndLnDel(__smart_timing(t2, lclk)) |
  		LCCR1_HorSnchWdth(__smart_timing(t3, lclk));
  
  	fbi->reg_lccr2 = LCCR2_DisHght(var->yres);
c1f99c215   Eric Miao   [ARM] pxafb: allo...
1216
1217
1218
  	fbi->reg_lccr3 = fbi->lccr3 | LCCR3_PixClkDiv(__smart_timing(t4, lclk));
  	fbi->reg_lccr3 |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HSP : 0;
  	fbi->reg_lccr3 |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VSP : 0;
3c42a4491   Eric Miao   pxafb: preliminar...
1219
1220
1221
1222
1223
1224
1225
  
  	/* FIXME: make this configurable */
  	fbi->reg_cmdcr = 1;
  }
  
  static int pxafb_smart_thread(void *arg)
  {
7f1133cbf   Eric Miao   pxafb: preliminar...
1226
  	struct pxafb_info *fbi = arg;
da2c3f0ea   Eric Miao   [ARM] pxafb: fix ...
1227
  	struct pxafb_mach_info *inf = fbi->dev->platform_data;
3c42a4491   Eric Miao   pxafb: preliminar...
1228

da2c3f0ea   Eric Miao   [ARM] pxafb: fix ...
1229
  	if (!inf->smart_update) {
3c42a4491   Eric Miao   pxafb: preliminar...
1230
1231
1232
1233
1234
  		pr_err("%s: not properly initialized, thread terminated
  ",
  				__func__);
  		return -EINVAL;
  	}
d2a34c13e   Julia Lawall   drivers/video: Mo...
1235
  	inf = fbi->dev->platform_data;
3c42a4491   Eric Miao   pxafb: preliminar...
1236
1237
1238
1239
1240
1241
1242
1243
1244
  
  	pr_debug("%s(): task starting
  ", __func__);
  
  	set_freezable();
  	while (!kthread_should_stop()) {
  
  		if (try_to_freeze())
  			continue;
07f651c72   Eric Miao   [ARM] pxafb: avoi...
1245
  		mutex_lock(&fbi->ctrlr_lock);
3c42a4491   Eric Miao   pxafb: preliminar...
1246
1247
1248
1249
  		if (fbi->state == C_ENABLE) {
  			inf->smart_update(&fbi->fb);
  			complete(&fbi->refresh_done);
  		}
07f651c72   Eric Miao   [ARM] pxafb: avoi...
1250
  		mutex_unlock(&fbi->ctrlr_lock);
3c42a4491   Eric Miao   pxafb: preliminar...
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
  		set_current_state(TASK_INTERRUPTIBLE);
  		schedule_timeout(30 * HZ / 1000);
  	}
  
  	pr_debug("%s(): task ending
  ", __func__);
  	return 0;
  }
  
  static int pxafb_smart_init(struct pxafb_info *fbi)
  {
07df1c4fe   Eric Miao   [ARM] pxafb: smal...
1262
  	if (!(fbi->lccr0 & LCCR0_LCDT))
6cc4abe43   Eric Miao   pxafb: only initi...
1263
  		return 0;
07df1c4fe   Eric Miao   [ARM] pxafb: smal...
1264
1265
1266
1267
1268
  	fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
  	fbi->n_smart_cmds = 0;
  
  	init_completion(&fbi->command_done);
  	init_completion(&fbi->refresh_done);
3c42a4491   Eric Miao   pxafb: preliminar...
1269
1270
1271
  	fbi->smart_thread = kthread_run(pxafb_smart_thread, fbi,
  					"lcd_refresh");
  	if (IS_ERR(fbi->smart_thread)) {
07df1c4fe   Eric Miao   [ARM] pxafb: smal...
1272
1273
  		pr_err("%s: unable to create kernel thread
  ", __func__);
3c42a4491   Eric Miao   pxafb: preliminar...
1274
1275
  		return PTR_ERR(fbi->smart_thread);
  	}
a5718a14a   Eric Miao   [ARM] pxafb: make...
1276

3c42a4491   Eric Miao   pxafb: preliminar...
1277
1278
1279
  	return 0;
  }
  #else
07df1c4fe   Eric Miao   [ARM] pxafb: smal...
1280
1281
  static inline int pxafb_smart_init(struct pxafb_info *fbi) { return 0; }
  #endif /* CONFIG_FB_PXA_SMARTPANEL */
3c42a4491   Eric Miao   pxafb: preliminar...
1282

90eabbf0e   Eric Miao   pxafb: move paral...
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
  static void setup_parallel_timing(struct pxafb_info *fbi,
  				  struct fb_var_screeninfo *var)
  {
  	unsigned int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
  
  	fbi->reg_lccr1 =
  		LCCR1_DisWdth(var->xres) +
  		LCCR1_HorSnchWdth(var->hsync_len) +
  		LCCR1_BegLnDel(var->left_margin) +
  		LCCR1_EndLnDel(var->right_margin);
  
  	/*
  	 * If we have a dual scan LCD, we need to halve
  	 * the YRES parameter.
  	 */
  	lines_per_panel = var->yres;
  	if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual)
  		lines_per_panel /= 2;
  
  	fbi->reg_lccr2 =
  		LCCR2_DisHght(lines_per_panel) +
  		LCCR2_VrtSnchWdth(var->vsync_len) +
  		LCCR2_BegFrmDel(var->upper_margin) +
  		LCCR2_EndFrmDel(var->lower_margin);
  
  	fbi->reg_lccr3 = fbi->lccr3 |
  		(var->sync & FB_SYNC_HOR_HIGH_ACT ?
  		 LCCR3_HorSnchH : LCCR3_HorSnchL) |
  		(var->sync & FB_SYNC_VERT_HIGH_ACT ?
  		 LCCR3_VrtSnchH : LCCR3_VrtSnchL);
  
  	if (pcd) {
  		fbi->reg_lccr3 |= LCCR3_PixClkDiv(pcd);
  		set_hsync_time(fbi, pcd);
  	}
  }
ba44cd2d8   Richard Purdie   [PATCH] pxafb: Ad...
1319
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1320
   * pxafb_activate_var():
b0086efba   eric miao   pxafb: fix variou...
1321
1322
   *	Configures LCD Controller based on entries in var parameter.
   *	Settings are only written to the controller if changes were made.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
   */
b0086efba   eric miao   pxafb: fix variou...
1324
1325
  static int pxafb_activate_var(struct fb_var_screeninfo *var,
  			      struct pxafb_info *fbi)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
  	u_long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328

90eabbf0e   Eric Miao   pxafb: move paral...
1329
1330
  	/* Update shadow copy atomically */
  	local_irq_save(flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331

3c42a4491   Eric Miao   pxafb: preliminar...
1332
1333
1334
1335
1336
1337
  #ifdef CONFIG_FB_PXA_SMARTPANEL
  	if (fbi->lccr0 & LCCR0_LCDT)
  		setup_smart_timing(fbi, var);
  	else
  #endif
  		setup_parallel_timing(fbi, var);
90eabbf0e   Eric Miao   pxafb: move paral...
1338

448ac4797   Sven Neumann   pxafb: use passed...
1339
  	setup_base_frame(fbi, var, 0);
6e354846e   Eric Miao   [ARM] pxafb: add ...
1340

90eabbf0e   Eric Miao   pxafb: move paral...
1341
  	fbi->reg_lccr0 = fbi->lccr0 |
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1342
  		(LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
b0086efba   eric miao   pxafb: fix variou...
1343
  		 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1344

878f57831   Eric Miao   [ARM] pxafb: clea...
1345
  	fbi->reg_lccr3 |= pxafb_var_to_lccr3(var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346

a7535ba73   Eric Miao   pxafb: introduce ...
1347
  	fbi->reg_lccr4 = lcd_readl(fbi, LCCR4) & ~LCCR4_PAL_FOR_MASK;
9ffa73960   Hans J. Koch   pxafb: Add suppor...
1348
  	fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
1350
1351
1352
1353
1354
  	local_irq_restore(flags);
  
  	/*
  	 * Only update the registers if the controller is enabled
  	 * and something has changed.
  	 */
a7535ba73   Eric Miao   pxafb: introduce ...
1355
1356
1357
1358
  	if ((lcd_readl(fbi, LCCR0) != fbi->reg_lccr0) ||
  	    (lcd_readl(fbi, LCCR1) != fbi->reg_lccr1) ||
  	    (lcd_readl(fbi, LCCR2) != fbi->reg_lccr2) ||
  	    (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) ||
a0427509a   Eric Miao   [ARM] pxafb: add ...
1359
  	    (lcd_readl(fbi, LCCR4) != fbi->reg_lccr4) ||
a7535ba73   Eric Miao   pxafb: introduce ...
1360
  	    (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) ||
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
1361
1362
  	    ((fbi->lccr0 & LCCR0_SDS) &&
  	    (lcd_readl(fbi, FDADR1) != fbi->fdadr[1])))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
  		pxafb_schedule_work(fbi, C_REENABLE);
  
  	return 0;
  }
  
  /*
   * NOTE!  The following functions are purely helpers for set_ctrlr_state.
   * Do not call them directly; set_ctrlr_state does the correct serialisation
   * to ensure that things happen in the right way 100% of time time.
   *	-- rmk
   */
  static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
  {
ca5da7106   Russell King   [ARM] pxafb: Remo...
1376
1377
  	pr_debug("pxafb: backlight o%s
  ", on ? "n" : "ff");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378

a5718a14a   Eric Miao   [ARM] pxafb: make...
1379
1380
  	if (fbi->backlight_power)
  		fbi->backlight_power(on);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
1382
1383
1384
  }
  
  static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
  {
ca5da7106   Russell King   [ARM] pxafb: Remo...
1385
1386
  	pr_debug("pxafb: LCD power o%s
  ", on ? "n" : "ff");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387

a5718a14a   Eric Miao   [ARM] pxafb: make...
1388
1389
  	if (fbi->lcd_power)
  		fbi->lcd_power(on, &fbi->fb.var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391
1392
  static void pxafb_enable_controller(struct pxafb_info *fbi)
  {
ca5da7106   Russell King   [ARM] pxafb: Remo...
1393
1394
  	pr_debug("pxafb: Enabling LCD controller
  ");
2c42dd8eb   eric miao   pxafb: introduce ...
1395
1396
1397
1398
  	pr_debug("fdadr0 0x%08x
  ", (unsigned int) fbi->fdadr[0]);
  	pr_debug("fdadr1 0x%08x
  ", (unsigned int) fbi->fdadr[1]);
ca5da7106   Russell King   [ARM] pxafb: Remo...
1399
1400
1401
1402
1403
1404
1405
1406
  	pr_debug("reg_lccr0 0x%08x
  ", (unsigned int) fbi->reg_lccr0);
  	pr_debug("reg_lccr1 0x%08x
  ", (unsigned int) fbi->reg_lccr1);
  	pr_debug("reg_lccr2 0x%08x
  ", (unsigned int) fbi->reg_lccr2);
  	pr_debug("reg_lccr3 0x%08x
  ", (unsigned int) fbi->reg_lccr3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407

8d3722667   Nicolas Pitre   [PATCH] ARM: 2846...
1408
  	/* enable LCD controller clock */
72e3524c0   Russell King   [ARM] pxa: update...
1409
  	clk_enable(fbi->clk);
8d3722667   Nicolas Pitre   [PATCH] ARM: 2846...
1410

3c42a4491   Eric Miao   pxafb: preliminar...
1411
1412
  	if (fbi->lccr0 & LCCR0_LCDT)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413
  	/* Sequence from 11.7.10 */
a0427509a   Eric Miao   [ARM] pxafb: add ...
1414
  	lcd_writel(fbi, LCCR4, fbi->reg_lccr4);
a7535ba73   Eric Miao   pxafb: introduce ...
1415
1416
1417
1418
1419
1420
  	lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
  	lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
  	lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
  	lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
  
  	lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
1b98d7c44   Vasily Khoruzhick   ARM: pxafb: rewor...
1421
1422
  	if (fbi->lccr0 & LCCR0_SDS)
  		lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
a7535ba73   Eric Miao   pxafb: introduce ...
1423
  	lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1424
1425
1426
1427
  }
  
  static void pxafb_disable_controller(struct pxafb_info *fbi)
  {
ce4fb7b89   eric miao   pxafb: convert fb...
1428
  	uint32_t lccr0;
3c42a4491   Eric Miao   pxafb: preliminar...
1429
1430
1431
1432
1433
1434
1435
  #ifdef CONFIG_FB_PXA_SMARTPANEL
  	if (fbi->lccr0 & LCCR0_LCDT) {
  		wait_for_completion_timeout(&fbi->refresh_done,
  				200 * HZ / 1000);
  		return;
  	}
  #endif
ce4fb7b89   eric miao   pxafb: convert fb...
1436
  	/* Clear LCD Status Register */
a7535ba73   Eric Miao   pxafb: introduce ...
1437
  	lcd_writel(fbi, LCSR, 0xffffffff);
ce4fb7b89   eric miao   pxafb: convert fb...
1438

a7535ba73   Eric Miao   pxafb: introduce ...
1439
1440
1441
  	lccr0 = lcd_readl(fbi, LCCR0) & ~LCCR0_LDM;
  	lcd_writel(fbi, LCCR0, lccr0);
  	lcd_writel(fbi, LCCR0, lccr0 | LCCR0_DIS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442

2ba162b93   Eric Miao   pxafb: use comple...
1443
  	wait_for_completion_timeout(&fbi->disable_done, 200 * HZ / 1000);
8d3722667   Nicolas Pitre   [PATCH] ARM: 2846...
1444
1445
  
  	/* disable LCD controller clock */
72e3524c0   Russell King   [ARM] pxa: update...
1446
  	clk_disable(fbi->clk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1447
1448
1449
1450
1451
  }
  
  /*
   *  pxafb_handle_irq: Handle 'LCD DONE' interrupts.
   */
7d12e780e   David Howells   IRQ: Maintain reg...
1452
  static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
1454
  {
  	struct pxafb_info *fbi = dev_id;
ff14ed5db   Denis V. Lunev   pxafb: lcsr1 is u...
1455
  	unsigned int lccr0, lcsr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456

198fc108e   Eric Miao   [ARM] pxafb: add ...
1457
  	lcsr = lcd_readl(fbi, LCSR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
  	if (lcsr & LCSR_LDD) {
a7535ba73   Eric Miao   pxafb: introduce ...
1459
1460
  		lccr0 = lcd_readl(fbi, LCCR0);
  		lcd_writel(fbi, LCCR0, lccr0 | LCCR0_LDM);
2ba162b93   Eric Miao   pxafb: use comple...
1461
  		complete(&fbi->disable_done);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
  	}
3c42a4491   Eric Miao   pxafb: preliminar...
1463
1464
1465
1466
  #ifdef CONFIG_FB_PXA_SMARTPANEL
  	if (lcsr & LCSR_CMD_INT)
  		complete(&fbi->command_done);
  #endif
a7535ba73   Eric Miao   pxafb: introduce ...
1467
  	lcd_writel(fbi, LCSR, lcsr);
198fc108e   Eric Miao   [ARM] pxafb: add ...
1468
1469
  
  #ifdef CONFIG_FB_PXA_OVERLAY
ff14ed5db   Denis V. Lunev   pxafb: lcsr1 is u...
1470
1471
1472
1473
  	{
  		unsigned int lcsr1 = lcd_readl(fbi, LCSR1);
  		if (lcsr1 & LCSR1_BS(1))
  			complete(&fbi->overlay[0].branch_done);
198fc108e   Eric Miao   [ARM] pxafb: add ...
1474

ff14ed5db   Denis V. Lunev   pxafb: lcsr1 is u...
1475
1476
  		if (lcsr1 & LCSR1_BS(2))
  			complete(&fbi->overlay[1].branch_done);
198fc108e   Eric Miao   [ARM] pxafb: add ...
1477

ff14ed5db   Denis V. Lunev   pxafb: lcsr1 is u...
1478
1479
  		lcd_writel(fbi, LCSR1, lcsr1);
  	}
198fc108e   Eric Miao   [ARM] pxafb: add ...
1480
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
  	return IRQ_HANDLED;
  }
  
  /*
   * This function must be called from task context only, since it will
   * sleep when disabling the LCD controller, or if we get two contending
   * processes trying to alter state.
   */
  static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
  {
  	u_int old_state;
b91dbce56   Matthias Kaehlcke   pxafb: convert ct...
1492
  	mutex_lock(&fbi->ctrlr_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
  
  	old_state = fbi->state;
  
  	/*
  	 * Hack around fbcon initialisation.
  	 */
  	if (old_state == C_STARTUP && state == C_REENABLE)
  		state = C_ENABLE;
  
  	switch (state) {
  	case C_DISABLE_CLKCHANGE:
  		/*
  		 * Disable controller for clock change.  If the
  		 * controller is already disabled, then do nothing.
  		 */
  		if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
  			fbi->state = state;
b0086efba   eric miao   pxafb: fix variou...
1510
  			/* TODO __pxafb_lcd_power(fbi, 0); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
  			pxafb_disable_controller(fbi);
  		}
  		break;
  
  	case C_DISABLE_PM:
  	case C_DISABLE:
  		/*
  		 * Disable controller
  		 */
  		if (old_state != C_DISABLE) {
  			fbi->state = state;
  			__pxafb_backlight_power(fbi, 0);
  			__pxafb_lcd_power(fbi, 0);
  			if (old_state != C_DISABLE_CLKCHANGE)
  				pxafb_disable_controller(fbi);
  		}
  		break;
  
  	case C_ENABLE_CLKCHANGE:
  		/*
  		 * Enable the controller after clock change.  Only
  		 * do this if we were disabled for the clock change.
  		 */
  		if (old_state == C_DISABLE_CLKCHANGE) {
  			fbi->state = C_ENABLE;
  			pxafb_enable_controller(fbi);
b0086efba   eric miao   pxafb: fix variou...
1537
  			/* TODO __pxafb_lcd_power(fbi, 1); */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
  		}
  		break;
  
  	case C_REENABLE:
  		/*
  		 * Re-enable the controller only if it was already
  		 * enabled.  This is so we reprogram the control
  		 * registers.
  		 */
  		if (old_state == C_ENABLE) {
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
1548
  			__pxafb_lcd_power(fbi, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
  			pxafb_disable_controller(fbi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1550
  			pxafb_enable_controller(fbi);
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
1551
  			__pxafb_lcd_power(fbi, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
  		}
  		break;
  
  	case C_ENABLE_PM:
  		/*
  		 * Re-enable the controller after PM.  This is not
  		 * perfect - think about the case where we were doing
  		 * a clock change, and we suspended half-way through.
  		 */
  		if (old_state != C_DISABLE_PM)
  			break;
  		/* fall through */
  
  	case C_ENABLE:
  		/*
  		 * Power up the LCD screen, enable controller, and
  		 * turn on the backlight.
  		 */
  		if (old_state != C_ENABLE) {
  			fbi->state = C_ENABLE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
1573
1574
1575
1576
1577
  			pxafb_enable_controller(fbi);
  			__pxafb_lcd_power(fbi, 1);
  			__pxafb_backlight_power(fbi, 1);
  		}
  		break;
  	}
b91dbce56   Matthias Kaehlcke   pxafb: convert ct...
1578
  	mutex_unlock(&fbi->ctrlr_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579
1580
1581
1582
1583
1584
  }
  
  /*
   * Our LCD controller task (which is called when we blank or unblank)
   * via keventd.
   */
6d5aefb8e   David Howells   WorkQueue: Fix up...
1585
  static void pxafb_task(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
  {
6d5aefb8e   David Howells   WorkQueue: Fix up...
1587
1588
  	struct pxafb_info *fbi =
  		container_of(work, struct pxafb_info, task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
  	u_int state = xchg(&fbi->task_state, -1);
  
  	set_ctrlr_state(fbi, state);
  }
  
  #ifdef CONFIG_CPU_FREQ
  /*
   * CPU clock speed change handler.  We need to adjust the LCD timing
   * parameters when the CPU clock is adjusted by the power management
   * subsystem.
   *
   * TODO: Determine why f->new != 10*get_lclk_frequency_10khz()
   */
  static int
  pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
  {
  	struct pxafb_info *fbi = TO_INF(nb, freq_transition);
b0086efba   eric miao   pxafb: fix variou...
1606
  	/* TODO struct cpufreq_freqs *f = data; */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607
1608
1609
1610
  	u_int pcd;
  
  	switch (val) {
  	case CPUFREQ_PRECHANGE:
a6d710fef   Marek Vasut   ARM: pxafb: Fix a...
1611
1612
1613
  #ifdef CONFIG_FB_PXA_OVERLAY
  		if (!(fbi->overlay[0].usage || fbi->overlay[1].usage))
  #endif
27be9a9e3   Vasily Khoruzhick   ARM: pxafb: don't...
1614
  			set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
1616
1617
  		break;
  
  	case CPUFREQ_POSTCHANGE:
72e3524c0   Russell King   [ARM] pxa: update...
1618
  		pcd = get_pcd(fbi, fbi->fb.var.pixclock);
ba44cd2d8   Richard Purdie   [PATCH] pxafb: Ad...
1619
  		set_hsync_time(fbi, pcd);
b0086efba   eric miao   pxafb: fix variou...
1620
1621
  		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) |
  				  LCCR3_PixClkDiv(pcd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
  		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
  		break;
  	}
  	return 0;
  }
  
  static int
  pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data)
  {
  	struct pxafb_info *fbi = TO_INF(nb, freq_policy);
  	struct fb_var_screeninfo *var = &fbi->fb.var;
  	struct cpufreq_policy *policy = data;
  
  	switch (val) {
  	case CPUFREQ_ADJUST:
  	case CPUFREQ_INCOMPATIBLE:
ac2bf5bdc   Holger Schurig   [ARM] 4828/1: fix...
1638
  		pr_debug("min dma period: %d ps, "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1639
1640
1641
  			"new clock %d kHz
  ", pxafb_display_dma_period(var),
  			policy->max);
b0086efba   eric miao   pxafb: fix variou...
1642
  		/* TODO: fill in min/max values */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1643
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
  	}
  	return 0;
  }
  #endif
  
  #ifdef CONFIG_PM
  /*
   * Power management hooks.  Note that we won't be called from IRQ context,
   * unlike the blank functions above, so we may sleep.
   */
4f3edfe38   Mike Rapoport   [ARM] pxa: update...
1654
  static int pxafb_suspend(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1655
  {
4f3edfe38   Mike Rapoport   [ARM] pxa: update...
1656
  	struct pxafb_info *fbi = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1657

9480e307c   Russell King   [PATCH] DRIVER MO...
1658
  	set_ctrlr_state(fbi, C_DISABLE_PM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1659
1660
  	return 0;
  }
4f3edfe38   Mike Rapoport   [ARM] pxa: update...
1661
  static int pxafb_resume(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662
  {
4f3edfe38   Mike Rapoport   [ARM] pxa: update...
1663
  	struct pxafb_info *fbi = dev_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664

9480e307c   Russell King   [PATCH] DRIVER MO...
1665
  	set_ctrlr_state(fbi, C_ENABLE_PM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
1667
  	return 0;
  }
4f3edfe38   Mike Rapoport   [ARM] pxa: update...
1668

471452104   Alexey Dobriyan   const: constify r...
1669
  static const struct dev_pm_ops pxafb_pm_ops = {
4f3edfe38   Mike Rapoport   [ARM] pxa: update...
1670
1671
1672
  	.suspend	= pxafb_suspend,
  	.resume		= pxafb_resume,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673
  #endif
77e196752   Eric Miao   [ARM] pxafb: allo...
1674
  static int __devinit pxafb_init_video_memory(struct pxafb_info *fbi)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1675
  {
77e196752   Eric Miao   [ARM] pxafb: allo...
1676
  	int size = PAGE_ALIGN(fbi->video_mem_size);
3c42a4491   Eric Miao   pxafb: preliminar...
1677

77e196752   Eric Miao   [ARM] pxafb: allo...
1678
1679
1680
  	fbi->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
  	if (fbi->video_mem == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1681

77e196752   Eric Miao   [ARM] pxafb: allo...
1682
1683
  	fbi->video_mem_phys = virt_to_phys(fbi->video_mem);
  	fbi->video_mem_size = size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1684

77e196752   Eric Miao   [ARM] pxafb: allo...
1685
1686
1687
  	fbi->fb.fix.smem_start	= fbi->video_mem_phys;
  	fbi->fb.fix.smem_len	= fbi->video_mem_size;
  	fbi->fb.screen_base	= fbi->video_mem;
84f43c308   eric miao   pxafb: introduce ...
1688

77e196752   Eric Miao   [ARM] pxafb: allo...
1689
  	return fbi->video_mem ? 0 : -ENOMEM;
84f43c308   eric miao   pxafb: introduce ...
1690
  }
ebdf982aa   Guennadi Liakhovetski   [ARM] 5028/1: pxa...
1691
1692
  static void pxafb_decode_mach_info(struct pxafb_info *fbi,
  				   struct pxafb_mach_info *inf)
84f43c308   eric miao   pxafb: introduce ...
1693
1694
  {
  	unsigned int lcd_conn = inf->lcd_conn;
77e196752   Eric Miao   [ARM] pxafb: allo...
1695
1696
  	struct pxafb_mode_info *m;
  	int i;
84f43c308   eric miao   pxafb: introduce ...
1697
1698
1699
  
  	fbi->cmap_inverse	= inf->cmap_inverse;
  	fbi->cmap_static	= inf->cmap_static;
a0427509a   Eric Miao   [ARM] pxafb: add ...
1700
  	fbi->lccr4 		= inf->lccr4;
84f43c308   eric miao   pxafb: introduce ...
1701

1ec26db1f   Eric Miao   pxafb: introduce ...
1702
  	switch (lcd_conn & LCD_TYPE_MASK) {
84f43c308   eric miao   pxafb: introduce ...
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
  	case LCD_TYPE_MONO_STN:
  		fbi->lccr0 = LCCR0_CMS;
  		break;
  	case LCD_TYPE_MONO_DSTN:
  		fbi->lccr0 = LCCR0_CMS | LCCR0_SDS;
  		break;
  	case LCD_TYPE_COLOR_STN:
  		fbi->lccr0 = 0;
  		break;
  	case LCD_TYPE_COLOR_DSTN:
  		fbi->lccr0 = LCCR0_SDS;
  		break;
  	case LCD_TYPE_COLOR_TFT:
  		fbi->lccr0 = LCCR0_PAS;
  		break;
  	case LCD_TYPE_SMART_PANEL:
  		fbi->lccr0 = LCCR0_LCDT | LCCR0_PAS;
  		break;
  	default:
  		/* fall back to backward compatibility way */
  		fbi->lccr0 = inf->lccr0;
  		fbi->lccr3 = inf->lccr3;
ebdf982aa   Guennadi Liakhovetski   [ARM] 5028/1: pxa...
1725
  		goto decode_mode;
84f43c308   eric miao   pxafb: introduce ...
1726
1727
1728
1729
  	}
  
  	if (lcd_conn == LCD_MONO_STN_8BPP)
  		fbi->lccr0 |= LCCR0_DPD;
9a1ac7e49   Eric Miao   [ARM] pxafb: add ...
1730
  	fbi->lccr0 |= (lcd_conn & LCD_ALTERNATE_MAPPING) ? LCCR0_LDDALT : 0;
84f43c308   eric miao   pxafb: introduce ...
1731
1732
1733
  	fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff);
  	fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0;
  	fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL)  ? LCCR3_PCP : 0;
ebdf982aa   Guennadi Liakhovetski   [ARM] 5028/1: pxa...
1734
  decode_mode:
77e196752   Eric Miao   [ARM] pxafb: allo...
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
  	pxafb_setmode(&fbi->fb.var, &inf->modes[0]);
  
  	/* decide video memory size as follows:
  	 * 1. default to mode of maximum resolution
  	 * 2. allow platform to override
  	 * 3. allow module parameter to override
  	 */
  	for (i = 0, m = &inf->modes[0]; i < inf->num_modes; i++, m++)
  		fbi->video_mem_size = max_t(size_t, fbi->video_mem_size,
  				m->xres * m->yres * m->bpp / 8);
  
  	if (inf->video_mem_size > fbi->video_mem_size)
  		fbi->video_mem_size = inf->video_mem_size;
  
  	if (video_mem_size > fbi->video_mem_size)
  		fbi->video_mem_size = video_mem_size;
84f43c308   eric miao   pxafb: introduce ...
1751
  }
9e6c29768   Jaya Kumar   [ARM] 5117/1: pxa...
1752
  static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
  {
  	struct pxafb_info *fbi;
  	void *addr;
  	struct pxafb_mach_info *inf = dev->platform_data;
  
  	/* Alloc the pxafb_info and pseudo_palette in one step */
  	fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
  	if (!fbi)
  		return NULL;
  
  	memset(fbi, 0, sizeof(struct pxafb_info));
  	fbi->dev = dev;
e0d8b13ae   Russell King   [ARM] pxa: don't ...
1765
  	fbi->clk = clk_get(dev, NULL);
72e3524c0   Russell King   [ARM] pxa: update...
1766
1767
1768
1769
  	if (IS_ERR(fbi->clk)) {
  		kfree(fbi);
  		return NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
1771
1772
1773
1774
  	strcpy(fbi->fb.fix.id, PXA_NAME);
  
  	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
  	fbi->fb.fix.type_aux	= 0;
  	fbi->fb.fix.xpanstep	= 0;
7e4b19c95   Eric Miao   [ARM] pxafb: allo...
1775
  	fbi->fb.fix.ypanstep	= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
1777
1778
1779
1780
1781
1782
  	fbi->fb.fix.ywrapstep	= 0;
  	fbi->fb.fix.accel	= FB_ACCEL_NONE;
  
  	fbi->fb.var.nonstd	= 0;
  	fbi->fb.var.activate	= FB_ACTIVATE_NOW;
  	fbi->fb.var.height	= -1;
  	fbi->fb.var.width	= -1;
7e4b19c95   Eric Miao   [ARM] pxafb: allo...
1783
  	fbi->fb.var.accel_flags	= FB_ACCELF_TEXT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
1786
1787
1788
1789
1790
1791
1792
  	fbi->fb.var.vmode	= FB_VMODE_NONINTERLACED;
  
  	fbi->fb.fbops		= &pxafb_ops;
  	fbi->fb.flags		= FBINFO_DEFAULT;
  	fbi->fb.node		= -1;
  
  	addr = fbi;
  	addr = addr + sizeof(struct pxafb_info);
  	fbi->fb.pseudo_palette	= addr;
b0086efba   eric miao   pxafb: fix variou...
1793
1794
  	fbi->state		= C_STARTUP;
  	fbi->task_state		= (u_char)-1;
d14b272bc   Richard Purdie   [ARM] 3848/1: pxa...
1795

84f43c308   eric miao   pxafb: introduce ...
1796
  	pxafb_decode_mach_info(fbi, inf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1797

7779cee3f   Vasily Khoruzhick   ARM: pxafb: fix p...
1798
1799
1800
1801
1802
  #ifdef CONFIG_FB_PXA_OVERLAY
  	/* place overlay(s) on top of base */
  	if (pxafb_overlay_supported())
  		fbi->lccr0 |= LCCR0_OUC;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
  	init_waitqueue_head(&fbi->ctrlr_wait);
6d5aefb8e   David Howells   WorkQueue: Fix up...
1804
  	INIT_WORK(&fbi->task, pxafb_task);
b91dbce56   Matthias Kaehlcke   pxafb: convert ct...
1805
  	mutex_init(&fbi->ctrlr_lock);
2ba162b93   Eric Miao   pxafb: use comple...
1806
  	init_completion(&fbi->disable_done);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807
1808
1809
1810
1811
  
  	return fbi;
  }
  
  #ifdef CONFIG_FB_PXA_PARAMETERS
9e6c29768   Jaya Kumar   [ARM] 5117/1: pxa...
1812
  static int __devinit parse_opt_mode(struct device *dev, const char *this_opt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
1814
  {
  	struct pxafb_mach_info *inf = dev->platform_data;
817daf14a   eric miao   pxafb: un-nest px...
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
  
  	const char *name = this_opt+5;
  	unsigned int namelen = strlen(name);
  	int res_specified = 0, bpp_specified = 0;
  	unsigned int xres = 0, yres = 0, bpp = 0;
  	int yres_specified = 0;
  	int i;
  	for (i = namelen-1; i >= 0; i--) {
  		switch (name[i]) {
  		case '-':
  			namelen = i;
  			if (!bpp_specified && !yres_specified) {
  				bpp = simple_strtoul(&name[i+1], NULL, 0);
  				bpp_specified = 1;
  			} else
  				goto done;
  			break;
  		case 'x':
  			if (!yres_specified) {
  				yres = simple_strtoul(&name[i+1], NULL, 0);
  				yres_specified = 1;
  			} else
  				goto done;
  			break;
  		case '0' ... '9':
  			break;
  		default:
  			goto done;
  		}
  	}
  	if (i < 0 && yres_specified) {
  		xres = simple_strtoul(name, NULL, 0);
  		res_specified = 1;
  	}
  done:
  	if (res_specified) {
  		dev_info(dev, "overriding resolution: %dx%d
  ", xres, yres);
  		inf->modes[0].xres = xres; inf->modes[0].yres = yres;
  	}
  	if (bpp_specified)
  		switch (bpp) {
  		case 1:
  		case 2:
  		case 4:
  		case 8:
  		case 16:
  			inf->modes[0].bpp = bpp;
  			dev_info(dev, "overriding bit depth: %d
  ", bpp);
  			break;
  		default:
  			dev_err(dev, "Depth %d is not valid
  ", bpp);
  			return -EINVAL;
  		}
  	return 0;
  }
9e6c29768   Jaya Kumar   [ARM] 5117/1: pxa...
1873
  static int __devinit parse_opt(struct device *dev, char *this_opt)
817daf14a   eric miao   pxafb: un-nest px...
1874
1875
1876
1877
1878
1879
  {
  	struct pxafb_mach_info *inf = dev->platform_data;
  	struct pxafb_mode_info *mode = &inf->modes[0];
  	char s[64];
  
  	s[0] = '\0';
77e196752   Eric Miao   [ARM] pxafb: allo...
1880
1881
1882
  	if (!strncmp(this_opt, "vmem:", 5)) {
  		video_mem_size = memparse(this_opt + 5, NULL);
  	} else if (!strncmp(this_opt, "mode:", 5)) {
817daf14a   eric miao   pxafb: un-nest px...
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
  		return parse_opt_mode(dev, this_opt);
  	} else if (!strncmp(this_opt, "pixclock:", 9)) {
  		mode->pixclock = simple_strtoul(this_opt+9, NULL, 0);
  		sprintf(s, "pixclock: %ld
  ", mode->pixclock);
  	} else if (!strncmp(this_opt, "left:", 5)) {
  		mode->left_margin = simple_strtoul(this_opt+5, NULL, 0);
  		sprintf(s, "left: %u
  ", mode->left_margin);
  	} else if (!strncmp(this_opt, "right:", 6)) {
  		mode->right_margin = simple_strtoul(this_opt+6, NULL, 0);
  		sprintf(s, "right: %u
  ", mode->right_margin);
  	} else if (!strncmp(this_opt, "upper:", 6)) {
  		mode->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
  		sprintf(s, "upper: %u
  ", mode->upper_margin);
  	} else if (!strncmp(this_opt, "lower:", 6)) {
  		mode->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
  		sprintf(s, "lower: %u
  ", mode->lower_margin);
  	} else if (!strncmp(this_opt, "hsynclen:", 9)) {
  		mode->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
  		sprintf(s, "hsynclen: %u
  ", mode->hsync_len);
  	} else if (!strncmp(this_opt, "vsynclen:", 9)) {
  		mode->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
  		sprintf(s, "vsynclen: %u
  ", mode->vsync_len);
  	} else if (!strncmp(this_opt, "hsync:", 6)) {
  		if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
  			sprintf(s, "hsync: Active Low
  ");
  			mode->sync &= ~FB_SYNC_HOR_HIGH_ACT;
  		} else {
  			sprintf(s, "hsync: Active High
  ");
  			mode->sync |= FB_SYNC_HOR_HIGH_ACT;
  		}
  	} else if (!strncmp(this_opt, "vsync:", 6)) {
  		if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
  			sprintf(s, "vsync: Active Low
  ");
  			mode->sync &= ~FB_SYNC_VERT_HIGH_ACT;
  		} else {
  			sprintf(s, "vsync: Active High
  ");
  			mode->sync |= FB_SYNC_VERT_HIGH_ACT;
  		}
  	} else if (!strncmp(this_opt, "dpc:", 4)) {
  		if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
  			sprintf(s, "double pixel clock: false
  ");
  			inf->lccr3 &= ~LCCR3_DPC;
  		} else {
  			sprintf(s, "double pixel clock: true
  ");
  			inf->lccr3 |= LCCR3_DPC;
  		}
  	} else if (!strncmp(this_opt, "outputen:", 9)) {
  		if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
  			sprintf(s, "output enable: active low
  ");
  			inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
  		} else {
  			sprintf(s, "output enable: active high
  ");
  			inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
  		}
  	} else if (!strncmp(this_opt, "pixclockpol:", 12)) {
  		if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
  			sprintf(s, "pixel clock polarity: falling edge
  ");
  			inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
  		} else {
  			sprintf(s, "pixel clock polarity: rising edge
  ");
  			inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
  		}
  	} else if (!strncmp(this_opt, "color", 5)) {
  		inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
  	} else if (!strncmp(this_opt, "mono", 4)) {
  		inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
  	} else if (!strncmp(this_opt, "active", 6)) {
  		inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
  	} else if (!strncmp(this_opt, "passive", 7)) {
  		inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
  	} else if (!strncmp(this_opt, "single", 6)) {
  		inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
  	} else if (!strncmp(this_opt, "dual", 4)) {
  		inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
  	} else if (!strncmp(this_opt, "4pix", 4)) {
  		inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
  	} else if (!strncmp(this_opt, "8pix", 4)) {
  		inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
  	} else {
  		dev_err(dev, "unknown option: %s
  ", this_opt);
  		return -EINVAL;
  	}
  
  	if (s[0] != '\0')
  		dev_info(dev, "override %s", s);
  
  	return 0;
  }
9e6c29768   Jaya Kumar   [ARM] 5117/1: pxa...
1989
  static int __devinit pxafb_parse_options(struct device *dev, char *options)
817daf14a   eric miao   pxafb: un-nest px...
1990
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1991
  	char *this_opt;
817daf14a   eric miao   pxafb: un-nest px...
1992
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1993

817daf14a   eric miao   pxafb: un-nest px...
1994
1995
  	if (!options || !*options)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1996
1997
1998
1999
2000
  
  	dev_dbg(dev, "options are \"%s\"
  ", options ? options : "null");
  
  	/* could be made table driven or similar?... */
817daf14a   eric miao   pxafb: un-nest px...
2001
2002
2003
2004
2005
2006
  	while ((this_opt = strsep(&options, ",")) != NULL) {
  		ret = parse_opt(dev, this_opt);
  		if (ret)
  			return ret;
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2007
  }
92ac73c1e   eric miao   pxafb: sanitize t...
2008
2009
  
  static char g_options[256] __devinitdata = "";
f1edfc420   Jaya Kumar   [ARM] 5115/1: pxa...
2010
  #ifndef MODULE
9e6c29768   Jaya Kumar   [ARM] 5117/1: pxa...
2011
  static int __init pxafb_setup_options(void)
92ac73c1e   eric miao   pxafb: sanitize t...
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
  {
  	char *options = NULL;
  
  	if (fb_get_options("pxafb", &options))
  		return -ENODEV;
  
  	if (options)
  		strlcpy(g_options, options, sizeof(g_options));
  
  	return 0;
  }
  #else
  #define pxafb_setup_options()		(0)
  
  module_param_string(options, g_options, sizeof(g_options), 0);
  MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
  #endif
  
  #else
  #define pxafb_parse_options(...)	(0)
  #define pxafb_setup_options()		(0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2033
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2034
  #ifdef DEBUG_VAR
4f3e26646   Eric Miao   [ARM] pxafb: fix ...
2035
2036
2037
2038
2039
2040
2041
  /* Check for various illegal bit-combinations. Currently only
   * a warning is given. */
  static void __devinit pxafb_check_options(struct device *dev,
  					  struct pxafb_mach_info *inf)
  {
  	if (inf->lcd_conn)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2042

b0086efba   eric miao   pxafb: fix variou...
2043
  	if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
4f3e26646   Eric Miao   [ARM] pxafb: fix ...
2044
  		dev_warn(dev, "machine LCCR0 setting contains "
b0086efba   eric miao   pxafb: fix variou...
2045
2046
2047
2048
  				"illegal bits: %08x
  ",
  			inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
  	if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
4f3e26646   Eric Miao   [ARM] pxafb: fix ...
2049
  		dev_warn(dev, "machine LCCR3 setting contains "
b0086efba   eric miao   pxafb: fix variou...
2050
2051
2052
2053
  				"illegal bits: %08x
  ",
  			inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
  	if (inf->lccr0 & LCCR0_DPD &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
2055
2056
  	    ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
  	     (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
  	     (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
4f3e26646   Eric Miao   [ARM] pxafb: fix ...
2057
  		dev_warn(dev, "Double Pixel Data (DPD) mode is "
b0086efba   eric miao   pxafb: fix variou...
2058
2059
2060
2061
  				"only valid in passive mono"
  				" single panel mode
  ");
  	if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2062
  	    (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
4f3e26646   Eric Miao   [ARM] pxafb: fix ...
2063
2064
  		dev_warn(dev, "Dual panel only valid in passive mode
  ");
b0086efba   eric miao   pxafb: fix variou...
2065
2066
  	if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
  	     (inf->modes->upper_margin || inf->modes->lower_margin))
4f3e26646   Eric Miao   [ARM] pxafb: fix ...
2067
  		dev_warn(dev, "Upper and lower margins must be 0 in "
b0086efba   eric miao   pxafb: fix variou...
2068
2069
  				"passive mode
  ");
4f3e26646   Eric Miao   [ARM] pxafb: fix ...
2070
2071
2072
  }
  #else
  #define pxafb_check_options(...)	do {} while (0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
  #endif
4f3e26646   Eric Miao   [ARM] pxafb: fix ...
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
  static int __devinit pxafb_probe(struct platform_device *dev)
  {
  	struct pxafb_info *fbi;
  	struct pxafb_mach_info *inf;
  	struct resource *r;
  	int irq, ret;
  
  	dev_dbg(&dev->dev, "pxafb_probe
  ");
  
  	inf = dev->dev.platform_data;
  	ret = -ENOMEM;
  	fbi = NULL;
  	if (!inf)
  		goto failed;
  
  	ret = pxafb_parse_options(&dev->dev, g_options);
  	if (ret < 0)
  		goto failed;
  
  	pxafb_check_options(&dev->dev, inf);
b0086efba   eric miao   pxafb: fix variou...
2095
2096
2097
2098
2099
2100
2101
2102
  	dev_dbg(&dev->dev, "got a %dx%dx%d LCD
  ",
  			inf->modes->xres,
  			inf->modes->yres,
  			inf->modes->bpp);
  	if (inf->modes->xres == 0 ||
  	    inf->modes->yres == 0 ||
  	    inf->modes->bpp == 0) {
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2103
2104
  		dev_err(&dev->dev, "Invalid resolution or bit depth
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2105
2106
2107
  		ret = -EINVAL;
  		goto failed;
  	}
a5718a14a   Eric Miao   [ARM] pxafb: make...
2108

3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2109
  	fbi = pxafb_init_fbinfo(&dev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2110
  	if (!fbi) {
b0086efba   eric miao   pxafb: fix variou...
2111
  		/* only reason for pxafb_init_fbinfo to fail is kmalloc */
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2112
2113
  		dev_err(&dev->dev, "Failed to initialize framebuffer device
  ");
b0086efba   eric miao   pxafb: fix variou...
2114
  		ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2115
2116
  		goto failed;
  	}
52a7a1cec   Daniel Mack   [ARM] pxafb: add ...
2117
2118
  	if (cpu_is_pxa3xx() && inf->acceleration_enabled)
  		fbi->fb.fix.accel = FB_ACCEL_PXA3XX;
a5718a14a   Eric Miao   [ARM] pxafb: make...
2119
2120
  	fbi->backlight_power = inf->pxafb_backlight_power;
  	fbi->lcd_power = inf->pxafb_lcd_power;
ce4fb7b89   eric miao   pxafb: convert fb...
2121
2122
2123
2124
2125
  	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
  	if (r == NULL) {
  		dev_err(&dev->dev, "no I/O memory resource defined
  ");
  		ret = -ENODEV;
ee98476bb   Jaya Kumar   [ARM] 5116/1: pxa...
2126
  		goto failed_fbi;
ce4fb7b89   eric miao   pxafb: convert fb...
2127
  	}
53eff4175   Daniel Mack   [ARM] pxafb: use ...
2128
  	r = request_mem_region(r->start, resource_size(r), dev->name);
ce4fb7b89   eric miao   pxafb: convert fb...
2129
2130
2131
2132
  	if (r == NULL) {
  		dev_err(&dev->dev, "failed to request I/O memory
  ");
  		ret = -EBUSY;
ee98476bb   Jaya Kumar   [ARM] 5116/1: pxa...
2133
  		goto failed_fbi;
ce4fb7b89   eric miao   pxafb: convert fb...
2134
  	}
53eff4175   Daniel Mack   [ARM] pxafb: use ...
2135
  	fbi->mmio_base = ioremap(r->start, resource_size(r));
ce4fb7b89   eric miao   pxafb: convert fb...
2136
2137
2138
2139
2140
2141
  	if (fbi->mmio_base == NULL) {
  		dev_err(&dev->dev, "failed to map I/O memory
  ");
  		ret = -EBUSY;
  		goto failed_free_res;
  	}
77e196752   Eric Miao   [ARM] pxafb: allo...
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
  	fbi->dma_buff_size = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
  	fbi->dma_buff = dma_alloc_coherent(fbi->dev, fbi->dma_buff_size,
  				&fbi->dma_buff_phys, GFP_KERNEL);
  	if (fbi->dma_buff == NULL) {
  		dev_err(&dev->dev, "failed to allocate memory for DMA
  ");
  		ret = -ENOMEM;
  		goto failed_free_io;
  	}
  
  	ret = pxafb_init_video_memory(fbi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2153
  	if (ret) {
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2154
2155
  		dev_err(&dev->dev, "Failed to allocate video RAM: %d
  ", ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2156
  		ret = -ENOMEM;
77e196752   Eric Miao   [ARM] pxafb: allo...
2157
  		goto failed_free_dma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2158
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2159

ce4fb7b89   eric miao   pxafb: convert fb...
2160
2161
2162
2163
2164
2165
2166
  	irq = platform_get_irq(dev, 0);
  	if (irq < 0) {
  		dev_err(&dev->dev, "no IRQ defined
  ");
  		ret = -ENODEV;
  		goto failed_free_mem;
  	}
f8798ccbe   Yong Zhang   video: irq: Remov...
2167
  	ret = request_irq(irq, pxafb_handle_irq, 0, "LCD", fbi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2168
  	if (ret) {
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2169
2170
  		dev_err(&dev->dev, "request_irq failed: %d
  ", ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171
  		ret = -EBUSY;
ce4fb7b89   eric miao   pxafb: convert fb...
2172
  		goto failed_free_mem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
  	}
3c42a4491   Eric Miao   pxafb: preliminar...
2174
2175
2176
2177
2178
2179
  	ret = pxafb_smart_init(fbi);
  	if (ret) {
  		dev_err(&dev->dev, "failed to initialize smartpanel
  ");
  		goto failed_free_irq;
  	}
07df1c4fe   Eric Miao   [ARM] pxafb: smal...
2180

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2181
2182
2183
2184
  	/*
  	 * This makes sure that our colour bitfield
  	 * descriptors are correctly initialised.
  	 */
ee98476bb   Jaya Kumar   [ARM] 5116/1: pxa...
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
  	ret = pxafb_check_var(&fbi->fb.var, &fbi->fb);
  	if (ret) {
  		dev_err(&dev->dev, "failed to get suitable mode
  ");
  		goto failed_free_irq;
  	}
  
  	ret = pxafb_set_par(&fbi->fb);
  	if (ret) {
  		dev_err(&dev->dev, "Failed to set parameters
  ");
  		goto failed_free_irq;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2198

3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2199
  	platform_set_drvdata(dev, fbi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2200
2201
2202
  
  	ret = register_framebuffer(&fbi->fb);
  	if (ret < 0) {
b0086efba   eric miao   pxafb: fix variou...
2203
2204
2205
  		dev_err(&dev->dev,
  			"Failed to register framebuffer device: %d
  ", ret);
ee98476bb   Jaya Kumar   [ARM] 5116/1: pxa...
2206
  		goto failed_free_cmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2207
  	}
198fc108e   Eric Miao   [ARM] pxafb: add ...
2208
  	pxafb_overlay_init(fbi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2209
2210
2211
  #ifdef CONFIG_CPU_FREQ
  	fbi->freq_transition.notifier_call = pxafb_freq_transition;
  	fbi->freq_policy.notifier_call = pxafb_freq_policy;
b0086efba   eric miao   pxafb: fix variou...
2212
2213
2214
2215
  	cpufreq_register_notifier(&fbi->freq_transition,
  				CPUFREQ_TRANSITION_NOTIFIER);
  	cpufreq_register_notifier(&fbi->freq_policy,
  				CPUFREQ_POLICY_NOTIFIER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2216
2217
2218
2219
2220
2221
2222
2223
  #endif
  
  	/*
  	 * Ok, now enable the LCD controller
  	 */
  	set_ctrlr_state(fbi, C_ENABLE);
  
  	return 0;
ee98476bb   Jaya Kumar   [ARM] 5116/1: pxa...
2224
2225
2226
  failed_free_cmap:
  	if (fbi->fb.cmap.len)
  		fb_dealloc_cmap(&fbi->fb.cmap);
ce4fb7b89   eric miao   pxafb: convert fb...
2227
2228
  failed_free_irq:
  	free_irq(irq, fbi);
ce4fb7b89   eric miao   pxafb: convert fb...
2229
  failed_free_mem:
77e196752   Eric Miao   [ARM] pxafb: allo...
2230
2231
2232
2233
  	free_pages_exact(fbi->video_mem, fbi->video_mem_size);
  failed_free_dma:
  	dma_free_coherent(&dev->dev, fbi->dma_buff_size,
  			fbi->dma_buff, fbi->dma_buff_phys);
ee98476bb   Jaya Kumar   [ARM] 5116/1: pxa...
2234
2235
2236
  failed_free_io:
  	iounmap(fbi->mmio_base);
  failed_free_res:
53eff4175   Daniel Mack   [ARM] pxafb: use ...
2237
  	release_mem_region(r->start, resource_size(r));
ee98476bb   Jaya Kumar   [ARM] 5116/1: pxa...
2238
2239
  failed_fbi:
  	clk_put(fbi->clk);
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2240
  	platform_set_drvdata(dev, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2241
  	kfree(fbi);
ee98476bb   Jaya Kumar   [ARM] 5116/1: pxa...
2242
  failed:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2243
2244
  	return ret;
  }
9f17f2874   Jaya Kumar   [ARM] 5118/1: pxa...
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
  static int __devexit pxafb_remove(struct platform_device *dev)
  {
  	struct pxafb_info *fbi = platform_get_drvdata(dev);
  	struct resource *r;
  	int irq;
  	struct fb_info *info;
  
  	if (!fbi)
  		return 0;
  
  	info = &fbi->fb;
198fc108e   Eric Miao   [ARM] pxafb: add ...
2256
  	pxafb_overlay_exit(fbi);
9f17f2874   Jaya Kumar   [ARM] 5118/1: pxa...
2257
2258
2259
2260
2261
2262
2263
2264
2265
  	unregister_framebuffer(info);
  
  	pxafb_disable_controller(fbi);
  
  	if (fbi->fb.cmap.len)
  		fb_dealloc_cmap(&fbi->fb.cmap);
  
  	irq = platform_get_irq(dev, 0);
  	free_irq(irq, fbi);
77e196752   Eric Miao   [ARM] pxafb: allo...
2266
2267
2268
2269
  	free_pages_exact(fbi->video_mem, fbi->video_mem_size);
  
  	dma_free_writecombine(&dev->dev, fbi->dma_buff_size,
  			fbi->dma_buff, fbi->dma_buff_phys);
9f17f2874   Jaya Kumar   [ARM] 5118/1: pxa...
2270
2271
2272
2273
  
  	iounmap(fbi->mmio_base);
  
  	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
53eff4175   Daniel Mack   [ARM] pxafb: use ...
2274
  	release_mem_region(r->start, resource_size(r));
9f17f2874   Jaya Kumar   [ARM] 5118/1: pxa...
2275
2276
2277
2278
2279
2280
  
  	clk_put(fbi->clk);
  	kfree(fbi);
  
  	return 0;
  }
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2281
  static struct platform_driver pxafb_driver = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2282
  	.probe		= pxafb_probe,
bdf602bd7   Russell King   [ARM] fix lots of...
2283
  	.remove 	= __devexit_p(pxafb_remove),
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2284
  	.driver		= {
9f17f2874   Jaya Kumar   [ARM] 5118/1: pxa...
2285
  		.owner	= THIS_MODULE,
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2286
  		.name	= "pxa2xx-fb",
4f3edfe38   Mike Rapoport   [ARM] pxa: update...
2287
2288
2289
  #ifdef CONFIG_PM
  		.pm	= &pxafb_pm_ops,
  #endif
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2290
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2291
  };
9e6c29768   Jaya Kumar   [ARM] 5117/1: pxa...
2292
  static int __init pxafb_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2293
  {
92ac73c1e   eric miao   pxafb: sanitize t...
2294
2295
  	if (pxafb_setup_options())
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2296

3ae5eaec1   Russell King   [DRIVER MODEL] Co...
2297
  	return platform_driver_register(&pxafb_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2298
  }
9f17f2874   Jaya Kumar   [ARM] 5118/1: pxa...
2299
2300
2301
2302
  static void __exit pxafb_exit(void)
  {
  	platform_driver_unregister(&pxafb_driver);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2303
  module_init(pxafb_init);
9f17f2874   Jaya Kumar   [ARM] 5118/1: pxa...
2304
  module_exit(pxafb_exit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2305
2306
2307
  
  MODULE_DESCRIPTION("loadable framebuffer driver for PXA");
  MODULE_LICENSE("GPL");