1 /*
2  * Framebuffer driver for TI OMAP boards
3  *
4  * Copyright (C) 2004 Nokia Corporation
5  * Author: Imre Deak <imre.deak@nokia.com>
6  *
7  * Acknowledgements:
8  *   Alex McMains <aam@ridgerun.com>       - Original driver
9  *   Juha Yrjola <juha.yrjola@nokia.com>   - Original driver and improvements
10  *   Dirk Behme <dirk.behme@de.bosch.com>  - changes for 2.6 kernel API
11  *   Texas Instruments                     - H3 support
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License as published by the
15  * Free Software Foundation; either version 2 of the License, or (at your
16  * option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27 #include <linux/platform_device.h>
28 #include <linux/mm.h>
29 #include <linux/slab.h>
30 #include <linux/uaccess.h>
31 
32 #include <plat/dma.h>
33 
34 #include "omapfb.h"
35 #include "lcdc.h"
36 #include "dispc.h"
37 
38 #define MODULE_NAME	"omapfb"
39 
40 static unsigned int	def_accel;
41 static unsigned long	def_vram[OMAPFB_PLANE_NUM];
42 static unsigned int	def_vram_cnt;
43 static unsigned long	def_vxres;
44 static unsigned long	def_vyres;
45 static unsigned int	def_rotate;
46 static unsigned int	def_mirror;
47 
48 #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
49 static int		manual_update = 1;
50 #else
51 static int		manual_update;
52 #endif
53 
54 static struct platform_device	*fbdev_pdev;
55 static struct lcd_panel		*fbdev_panel;
56 static struct omapfb_device	*omapfb_dev;
57 
58 struct caps_table_struct {
59 	unsigned long flag;
60 	const char *name;
61 };
62 
63 static struct caps_table_struct ctrl_caps[] = {
64 	{ OMAPFB_CAPS_MANUAL_UPDATE,  "manual update" },
65 	{ OMAPFB_CAPS_TEARSYNC,       "tearing synchronization" },
66 	{ OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" },
67 	{ OMAPFB_CAPS_PLANE_SCALE,    "scale plane" },
68 	{ OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" },
69 	{ OMAPFB_CAPS_WINDOW_SCALE,   "scale window" },
70 	{ OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" },
71 	{ OMAPFB_CAPS_WINDOW_ROTATE,  "rotate window" },
72 	{ OMAPFB_CAPS_SET_BACKLIGHT,  "backlight setting" },
73 };
74 
75 static struct caps_table_struct color_caps[] = {
76 	{ 1 << OMAPFB_COLOR_RGB565,	"RGB565", },
77 	{ 1 << OMAPFB_COLOR_YUV422,	"YUV422", },
78 	{ 1 << OMAPFB_COLOR_YUV420,	"YUV420", },
79 	{ 1 << OMAPFB_COLOR_CLUT_8BPP,	"CLUT8", },
80 	{ 1 << OMAPFB_COLOR_CLUT_4BPP,	"CLUT4", },
81 	{ 1 << OMAPFB_COLOR_CLUT_2BPP,	"CLUT2", },
82 	{ 1 << OMAPFB_COLOR_CLUT_1BPP,	"CLUT1", },
83 	{ 1 << OMAPFB_COLOR_RGB444,	"RGB444", },
84 	{ 1 << OMAPFB_COLOR_YUY422,	"YUY422", },
85 };
86 
omapdss_release(struct device * dev)87 static void omapdss_release(struct device *dev)
88 {
89 }
90 
91 /* dummy device for clocks */
92 static struct platform_device omapdss_device = {
93 	.name		= "omapdss",
94 	.id		= -1,
95 	.dev            = {
96 		.release = omapdss_release,
97 	},
98 };
99 
100 /*
101  * ---------------------------------------------------------------------------
102  * LCD panel
103  * ---------------------------------------------------------------------------
104  */
105 extern struct lcd_ctrl hwa742_ctrl;
106 extern struct lcd_ctrl blizzard_ctrl;
107 
108 static const struct lcd_ctrl *ctrls[] = {
109 #ifdef CONFIG_ARCH_OMAP1
110 	&omap1_int_ctrl,
111 #else
112 	&omap2_int_ctrl,
113 #endif
114 
115 #ifdef CONFIG_FB_OMAP_LCDC_HWA742
116 	&hwa742_ctrl,
117 #endif
118 #ifdef CONFIG_FB_OMAP_LCDC_BLIZZARD
119 	&blizzard_ctrl,
120 #endif
121 };
122 
123 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
124 #ifdef CONFIG_ARCH_OMAP1
125 extern struct lcd_ctrl_extif omap1_ext_if;
126 #else
127 extern struct lcd_ctrl_extif omap2_ext_if;
128 #endif
129 #endif
130 
omapfb_rqueue_lock(struct omapfb_device * fbdev)131 static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
132 {
133 	mutex_lock(&fbdev->rqueue_mutex);
134 }
135 
omapfb_rqueue_unlock(struct omapfb_device * fbdev)136 static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
137 {
138 	mutex_unlock(&fbdev->rqueue_mutex);
139 }
140 
141 /*
142  * ---------------------------------------------------------------------------
143  * LCD controller and LCD DMA
144  * ---------------------------------------------------------------------------
145  */
146 /* Lookup table to map elem size to elem type. */
147 static const int dma_elem_type[] = {
148 	0,
149 	OMAP_DMA_DATA_TYPE_S8,
150 	OMAP_DMA_DATA_TYPE_S16,
151 	0,
152 	OMAP_DMA_DATA_TYPE_S32,
153 };
154 
155 /*
156  * Allocate resources needed for LCD controller and LCD DMA operations. Video
157  * memory is allocated from system memory according to the virtual display
158  * size, except if a bigger memory size is specified explicitly as a kernel
159  * parameter.
160  */
ctrl_init(struct omapfb_device * fbdev)161 static int ctrl_init(struct omapfb_device *fbdev)
162 {
163 	int r;
164 	int i;
165 
166 	/* kernel/module vram parameters override boot tags/board config */
167 	if (def_vram_cnt) {
168 		for (i = 0; i < def_vram_cnt; i++)
169 			fbdev->mem_desc.region[i].size =
170 				PAGE_ALIGN(def_vram[i]);
171 		fbdev->mem_desc.region_cnt = i;
172 	} else {
173 		struct omapfb_platform_data *conf;
174 
175 		conf = fbdev->dev->platform_data;
176 		fbdev->mem_desc = conf->mem_desc;
177 	}
178 
179 	if (!fbdev->mem_desc.region_cnt) {
180 		struct lcd_panel *panel = fbdev->panel;
181 		int def_size;
182 		int bpp = panel->bpp;
183 
184 		/* 12 bpp is packed in 16 bits */
185 		if (bpp == 12)
186 			bpp = 16;
187 		def_size = def_vxres * def_vyres * bpp / 8;
188 		fbdev->mem_desc.region_cnt = 1;
189 		fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size);
190 	}
191 	r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc);
192 	if (r < 0) {
193 		dev_err(fbdev->dev, "controller initialization failed (%d)\n",
194 			r);
195 		return r;
196 	}
197 
198 #ifdef DEBUG
199 	for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
200 		dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n",
201 			 i,
202 			 fbdev->mem_desc.region[i].paddr,
203 			 fbdev->mem_desc.region[i].vaddr,
204 			 fbdev->mem_desc.region[i].size);
205 	}
206 #endif
207 	return 0;
208 }
209 
ctrl_cleanup(struct omapfb_device * fbdev)210 static void ctrl_cleanup(struct omapfb_device *fbdev)
211 {
212 	fbdev->ctrl->cleanup();
213 }
214 
215 /* Must be called with fbdev->rqueue_mutex held. */
ctrl_change_mode(struct fb_info * fbi)216 static int ctrl_change_mode(struct fb_info *fbi)
217 {
218 	int r;
219 	unsigned long offset;
220 	struct omapfb_plane_struct *plane = fbi->par;
221 	struct omapfb_device *fbdev = plane->fbdev;
222 	struct fb_var_screeninfo *var = &fbi->var;
223 
224 	offset = var->yoffset * fbi->fix.line_length +
225 		 var->xoffset * var->bits_per_pixel / 8;
226 
227 	if (fbdev->ctrl->sync)
228 		fbdev->ctrl->sync();
229 	r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out,
230 				 offset, var->xres_virtual,
231 				 plane->info.pos_x, plane->info.pos_y,
232 				 var->xres, var->yres, plane->color_mode);
233 	if (r < 0)
234 		return r;
235 
236 	if (fbdev->ctrl->set_rotate != NULL) {
237 		r = fbdev->ctrl->set_rotate(var->rotate);
238 		if (r < 0)
239 			return r;
240 	}
241 
242 	if (fbdev->ctrl->set_scale != NULL)
243 		r = fbdev->ctrl->set_scale(plane->idx,
244 				   var->xres, var->yres,
245 				   plane->info.out_width,
246 				   plane->info.out_height);
247 
248 	return r;
249 }
250 
251 /*
252  * ---------------------------------------------------------------------------
253  * fbdev framework callbacks and the ioctl interface
254  * ---------------------------------------------------------------------------
255  */
256 /* Called each time the omapfb device is opened */
omapfb_open(struct fb_info * info,int user)257 static int omapfb_open(struct fb_info *info, int user)
258 {
259 	return 0;
260 }
261 
262 static void omapfb_sync(struct fb_info *info);
263 
264 /* Called when the omapfb device is closed. We make sure that any pending
265  * gfx DMA operations are ended, before we return. */
omapfb_release(struct fb_info * info,int user)266 static int omapfb_release(struct fb_info *info, int user)
267 {
268 	omapfb_sync(info);
269 	return 0;
270 }
271 
272 /* Store a single color palette entry into a pseudo palette or the hardware
273  * palette if one is available. For now we support only 16bpp and thus store
274  * the entry only to the pseudo palette.
275  */
_setcolreg(struct fb_info * info,u_int regno,u_int red,u_int green,u_int blue,u_int transp,int update_hw_pal)276 static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
277 			u_int blue, u_int transp, int update_hw_pal)
278 {
279 	struct omapfb_plane_struct *plane = info->par;
280 	struct omapfb_device *fbdev = plane->fbdev;
281 	struct fb_var_screeninfo *var = &info->var;
282 	int r = 0;
283 
284 	switch (plane->color_mode) {
285 	case OMAPFB_COLOR_YUV422:
286 	case OMAPFB_COLOR_YUV420:
287 	case OMAPFB_COLOR_YUY422:
288 		r = -EINVAL;
289 		break;
290 	case OMAPFB_COLOR_CLUT_8BPP:
291 	case OMAPFB_COLOR_CLUT_4BPP:
292 	case OMAPFB_COLOR_CLUT_2BPP:
293 	case OMAPFB_COLOR_CLUT_1BPP:
294 		if (fbdev->ctrl->setcolreg)
295 			r = fbdev->ctrl->setcolreg(regno, red, green, blue,
296 							transp, update_hw_pal);
297 		/* Fallthrough */
298 	case OMAPFB_COLOR_RGB565:
299 	case OMAPFB_COLOR_RGB444:
300 		if (r != 0)
301 			break;
302 
303 		if (regno < 0) {
304 			r = -EINVAL;
305 			break;
306 		}
307 
308 		if (regno < 16) {
309 			u16 pal;
310 			pal = ((red >> (16 - var->red.length)) <<
311 					var->red.offset) |
312 			      ((green >> (16 - var->green.length)) <<
313 					var->green.offset) |
314 			      (blue >> (16 - var->blue.length));
315 			((u32 *)(info->pseudo_palette))[regno] = pal;
316 		}
317 		break;
318 	default:
319 		BUG();
320 	}
321 	return r;
322 }
323 
omapfb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int transp,struct fb_info * info)324 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
325 			    u_int transp, struct fb_info *info)
326 {
327 	return _setcolreg(info, regno, red, green, blue, transp, 1);
328 }
329 
omapfb_setcmap(struct fb_cmap * cmap,struct fb_info * info)330 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
331 {
332 	int count, index, r;
333 	u16 *red, *green, *blue, *transp;
334 	u16 trans = 0xffff;
335 
336 	red     = cmap->red;
337 	green   = cmap->green;
338 	blue    = cmap->blue;
339 	transp  = cmap->transp;
340 	index   = cmap->start;
341 
342 	for (count = 0; count < cmap->len; count++) {
343 		if (transp)
344 			trans = *transp++;
345 		r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
346 				count == cmap->len - 1);
347 		if (r != 0)
348 			return r;
349 	}
350 
351 	return 0;
352 }
353 
354 static int omapfb_update_full_screen(struct fb_info *fbi);
355 
omapfb_blank(int blank,struct fb_info * fbi)356 static int omapfb_blank(int blank, struct fb_info *fbi)
357 {
358 	struct omapfb_plane_struct *plane = fbi->par;
359 	struct omapfb_device *fbdev = plane->fbdev;
360 	int do_update = 0;
361 	int r = 0;
362 
363 	omapfb_rqueue_lock(fbdev);
364 	switch (blank) {
365 	case FB_BLANK_UNBLANK:
366 		if (fbdev->state == OMAPFB_SUSPENDED) {
367 			if (fbdev->ctrl->resume)
368 				fbdev->ctrl->resume();
369 			fbdev->panel->enable(fbdev->panel);
370 			fbdev->state = OMAPFB_ACTIVE;
371 			if (fbdev->ctrl->get_update_mode() ==
372 					OMAPFB_MANUAL_UPDATE)
373 				do_update = 1;
374 		}
375 		break;
376 	case FB_BLANK_POWERDOWN:
377 		if (fbdev->state == OMAPFB_ACTIVE) {
378 			fbdev->panel->disable(fbdev->panel);
379 			if (fbdev->ctrl->suspend)
380 				fbdev->ctrl->suspend();
381 			fbdev->state = OMAPFB_SUSPENDED;
382 		}
383 		break;
384 	default:
385 		r = -EINVAL;
386 	}
387 	omapfb_rqueue_unlock(fbdev);
388 
389 	if (r == 0 && do_update)
390 		r = omapfb_update_full_screen(fbi);
391 
392 	return r;
393 }
394 
omapfb_sync(struct fb_info * fbi)395 static void omapfb_sync(struct fb_info *fbi)
396 {
397 	struct omapfb_plane_struct *plane = fbi->par;
398 	struct omapfb_device *fbdev = plane->fbdev;
399 
400 	omapfb_rqueue_lock(fbdev);
401 	if (fbdev->ctrl->sync)
402 		fbdev->ctrl->sync();
403 	omapfb_rqueue_unlock(fbdev);
404 }
405 
406 /*
407  * Set fb_info.fix fields and also updates fbdev.
408  * When calling this fb_info.var must be set up already.
409  */
set_fb_fix(struct fb_info * fbi,int from_init)410 static void set_fb_fix(struct fb_info *fbi, int from_init)
411 {
412 	struct fb_fix_screeninfo *fix = &fbi->fix;
413 	struct fb_var_screeninfo *var = &fbi->var;
414 	struct omapfb_plane_struct *plane = fbi->par;
415 	struct omapfb_mem_region *rg;
416 	int bpp;
417 
418 	rg = &plane->fbdev->mem_desc.region[plane->idx];
419 	fbi->screen_base	= rg->vaddr;
420 
421 	if (!from_init) {
422 		mutex_lock(&fbi->mm_lock);
423 		fix->smem_start		= rg->paddr;
424 		fix->smem_len		= rg->size;
425 		mutex_unlock(&fbi->mm_lock);
426 	} else {
427 		fix->smem_start		= rg->paddr;
428 		fix->smem_len		= rg->size;
429 	}
430 
431 	fix->type = FB_TYPE_PACKED_PIXELS;
432 	bpp = var->bits_per_pixel;
433 	if (var->nonstd)
434 		fix->visual = FB_VISUAL_PSEUDOCOLOR;
435 	else switch (var->bits_per_pixel) {
436 	case 16:
437 	case 12:
438 		fix->visual = FB_VISUAL_TRUECOLOR;
439 		/* 12bpp is stored in 16 bits */
440 		bpp = 16;
441 		break;
442 	case 1:
443 	case 2:
444 	case 4:
445 	case 8:
446 		fix->visual = FB_VISUAL_PSEUDOCOLOR;
447 		break;
448 	}
449 	fix->accel		= FB_ACCEL_OMAP1610;
450 	fix->line_length	= var->xres_virtual * bpp / 8;
451 }
452 
set_color_mode(struct omapfb_plane_struct * plane,struct fb_var_screeninfo * var)453 static int set_color_mode(struct omapfb_plane_struct *plane,
454 			  struct fb_var_screeninfo *var)
455 {
456 	switch (var->nonstd) {
457 	case 0:
458 		break;
459 	case OMAPFB_COLOR_YUV422:
460 		var->bits_per_pixel = 16;
461 		plane->color_mode = var->nonstd;
462 		return 0;
463 	case OMAPFB_COLOR_YUV420:
464 		var->bits_per_pixel = 12;
465 		plane->color_mode = var->nonstd;
466 		return 0;
467 	case OMAPFB_COLOR_YUY422:
468 		var->bits_per_pixel = 16;
469 		plane->color_mode = var->nonstd;
470 		return 0;
471 	default:
472 		return -EINVAL;
473 	}
474 
475 	switch (var->bits_per_pixel) {
476 	case 1:
477 		plane->color_mode = OMAPFB_COLOR_CLUT_1BPP;
478 		return 0;
479 	case 2:
480 		plane->color_mode = OMAPFB_COLOR_CLUT_2BPP;
481 		return 0;
482 	case 4:
483 		plane->color_mode = OMAPFB_COLOR_CLUT_4BPP;
484 		return 0;
485 	case 8:
486 		plane->color_mode = OMAPFB_COLOR_CLUT_8BPP;
487 		return 0;
488 	case 12:
489 		var->bits_per_pixel = 16;
490 	case 16:
491 		if (plane->fbdev->panel->bpp == 12)
492 			plane->color_mode = OMAPFB_COLOR_RGB444;
493 		else
494 			plane->color_mode = OMAPFB_COLOR_RGB565;
495 		return 0;
496 	default:
497 		return -EINVAL;
498 	}
499 }
500 
501 /*
502  * Check the values in var against our capabilities and in case of out of
503  * bound values try to adjust them.
504  */
set_fb_var(struct fb_info * fbi,struct fb_var_screeninfo * var)505 static int set_fb_var(struct fb_info *fbi,
506 		      struct fb_var_screeninfo *var)
507 {
508 	int		bpp;
509 	unsigned long	max_frame_size;
510 	unsigned long	line_size;
511 	int		xres_min, xres_max;
512 	int		yres_min, yres_max;
513 	struct omapfb_plane_struct *plane = fbi->par;
514 	struct omapfb_device *fbdev = plane->fbdev;
515 	struct lcd_panel *panel = fbdev->panel;
516 
517 	if (set_color_mode(plane, var) < 0)
518 		return -EINVAL;
519 
520 	bpp = var->bits_per_pixel;
521 	if (plane->color_mode == OMAPFB_COLOR_RGB444)
522 		bpp = 16;
523 
524 	switch (var->rotate) {
525 	case 0:
526 	case 180:
527 		xres_min = OMAPFB_PLANE_XRES_MIN;
528 		xres_max = panel->x_res;
529 		yres_min = OMAPFB_PLANE_YRES_MIN;
530 		yres_max = panel->y_res;
531 		if (cpu_is_omap15xx()) {
532 			var->xres = panel->x_res;
533 			var->yres = panel->y_res;
534 		}
535 		break;
536 	case 90:
537 	case 270:
538 		xres_min = OMAPFB_PLANE_YRES_MIN;
539 		xres_max = panel->y_res;
540 		yres_min = OMAPFB_PLANE_XRES_MIN;
541 		yres_max = panel->x_res;
542 		if (cpu_is_omap15xx()) {
543 			var->xres = panel->y_res;
544 			var->yres = panel->x_res;
545 		}
546 		break;
547 	default:
548 		return -EINVAL;
549 	}
550 
551 	if (var->xres < xres_min)
552 		var->xres = xres_min;
553 	if (var->yres < yres_min)
554 		var->yres = yres_min;
555 	if (var->xres > xres_max)
556 		var->xres = xres_max;
557 	if (var->yres > yres_max)
558 		var->yres = yres_max;
559 
560 	if (var->xres_virtual < var->xres)
561 		var->xres_virtual = var->xres;
562 	if (var->yres_virtual < var->yres)
563 		var->yres_virtual = var->yres;
564 	max_frame_size = fbdev->mem_desc.region[plane->idx].size;
565 	line_size = var->xres_virtual * bpp / 8;
566 	if (line_size * var->yres_virtual > max_frame_size) {
567 		/* Try to keep yres_virtual first */
568 		line_size = max_frame_size / var->yres_virtual;
569 		var->xres_virtual = line_size * 8 / bpp;
570 		if (var->xres_virtual < var->xres) {
571 			/* Still doesn't fit. Shrink yres_virtual too */
572 			var->xres_virtual = var->xres;
573 			line_size = var->xres * bpp / 8;
574 			var->yres_virtual = max_frame_size / line_size;
575 		}
576 		/* Recheck this, as the virtual size changed. */
577 		if (var->xres_virtual < var->xres)
578 			var->xres = var->xres_virtual;
579 		if (var->yres_virtual < var->yres)
580 			var->yres = var->yres_virtual;
581 		if (var->xres < xres_min || var->yres < yres_min)
582 			return -EINVAL;
583 	}
584 	if (var->xres + var->xoffset > var->xres_virtual)
585 		var->xoffset = var->xres_virtual - var->xres;
586 	if (var->yres + var->yoffset > var->yres_virtual)
587 		var->yoffset = var->yres_virtual - var->yres;
588 
589 	if (plane->color_mode == OMAPFB_COLOR_RGB444) {
590 		var->red.offset	  = 8; var->red.length	 = 4;
591 						var->red.msb_right   = 0;
592 		var->green.offset = 4; var->green.length = 4;
593 						var->green.msb_right = 0;
594 		var->blue.offset  = 0; var->blue.length  = 4;
595 						var->blue.msb_right  = 0;
596 	} else {
597 		var->red.offset	 = 11; var->red.length	 = 5;
598 						var->red.msb_right   = 0;
599 		var->green.offset = 5;  var->green.length = 6;
600 						var->green.msb_right = 0;
601 		var->blue.offset = 0;  var->blue.length  = 5;
602 						var->blue.msb_right  = 0;
603 	}
604 
605 	var->height		= -1;
606 	var->width		= -1;
607 	var->grayscale		= 0;
608 
609 	/* pixclock in ps, the rest in pixclock */
610 	var->pixclock		= 10000000 / (panel->pixel_clock / 100);
611 	var->left_margin	= panel->hfp;
612 	var->right_margin	= panel->hbp;
613 	var->upper_margin	= panel->vfp;
614 	var->lower_margin	= panel->vbp;
615 	var->hsync_len		= panel->hsw;
616 	var->vsync_len		= panel->vsw;
617 
618 	/* TODO: get these from panel->config */
619 	var->vmode		= FB_VMODE_NONINTERLACED;
620 	var->sync		= 0;
621 
622 	return 0;
623 }
624 
625 
626 /* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
omapfb_rotate(struct fb_info * fbi,int rotate)627 static void omapfb_rotate(struct fb_info *fbi, int rotate)
628 {
629 	struct omapfb_plane_struct *plane = fbi->par;
630 	struct omapfb_device *fbdev = plane->fbdev;
631 
632 	omapfb_rqueue_lock(fbdev);
633 	if (rotate != fbi->var.rotate) {
634 		struct fb_var_screeninfo *new_var = &fbdev->new_var;
635 
636 		memcpy(new_var, &fbi->var, sizeof(*new_var));
637 		new_var->rotate = rotate;
638 		if (set_fb_var(fbi, new_var) == 0 &&
639 		    memcmp(new_var, &fbi->var, sizeof(*new_var))) {
640 			memcpy(&fbi->var, new_var, sizeof(*new_var));
641 			ctrl_change_mode(fbi);
642 		}
643 	}
644 	omapfb_rqueue_unlock(fbdev);
645 }
646 
647 /*
648  * Set new x,y offsets in the virtual display for the visible area and switch
649  * to the new mode.
650  */
omapfb_pan_display(struct fb_var_screeninfo * var,struct fb_info * fbi)651 static int omapfb_pan_display(struct fb_var_screeninfo *var,
652 			       struct fb_info *fbi)
653 {
654 	struct omapfb_plane_struct *plane = fbi->par;
655 	struct omapfb_device *fbdev = plane->fbdev;
656 	int r = 0;
657 
658 	omapfb_rqueue_lock(fbdev);
659 	if (var->xoffset != fbi->var.xoffset ||
660 	    var->yoffset != fbi->var.yoffset) {
661 		struct fb_var_screeninfo *new_var = &fbdev->new_var;
662 
663 		memcpy(new_var, &fbi->var, sizeof(*new_var));
664 		new_var->xoffset = var->xoffset;
665 		new_var->yoffset = var->yoffset;
666 		if (set_fb_var(fbi, new_var))
667 			r = -EINVAL;
668 		else {
669 			memcpy(&fbi->var, new_var, sizeof(*new_var));
670 			ctrl_change_mode(fbi);
671 		}
672 	}
673 	omapfb_rqueue_unlock(fbdev);
674 
675 	return r;
676 }
677 
678 /* Set mirror to vertical axis and switch to the new mode. */
omapfb_mirror(struct fb_info * fbi,int mirror)679 static int omapfb_mirror(struct fb_info *fbi, int mirror)
680 {
681 	struct omapfb_plane_struct *plane = fbi->par;
682 	struct omapfb_device *fbdev = plane->fbdev;
683 	int r = 0;
684 
685 	omapfb_rqueue_lock(fbdev);
686 	mirror = mirror ? 1 : 0;
687 	if (cpu_is_omap15xx())
688 		r = -EINVAL;
689 	else if (mirror != plane->info.mirror) {
690 		plane->info.mirror = mirror;
691 		r = ctrl_change_mode(fbi);
692 	}
693 	omapfb_rqueue_unlock(fbdev);
694 
695 	return r;
696 }
697 
698 /*
699  * Check values in var, try to adjust them in case of out of bound values if
700  * possible, or return error.
701  */
omapfb_check_var(struct fb_var_screeninfo * var,struct fb_info * fbi)702 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
703 {
704 	struct omapfb_plane_struct *plane = fbi->par;
705 	struct omapfb_device *fbdev = plane->fbdev;
706 	int r;
707 
708 	omapfb_rqueue_lock(fbdev);
709 	if (fbdev->ctrl->sync != NULL)
710 		fbdev->ctrl->sync();
711 	r = set_fb_var(fbi, var);
712 	omapfb_rqueue_unlock(fbdev);
713 
714 	return r;
715 }
716 
717 /*
718  * Switch to a new mode. The parameters for it has been check already by
719  * omapfb_check_var.
720  */
omapfb_set_par(struct fb_info * fbi)721 static int omapfb_set_par(struct fb_info *fbi)
722 {
723 	struct omapfb_plane_struct *plane = fbi->par;
724 	struct omapfb_device *fbdev = plane->fbdev;
725 	int r = 0;
726 
727 	omapfb_rqueue_lock(fbdev);
728 	set_fb_fix(fbi, 0);
729 	r = ctrl_change_mode(fbi);
730 	omapfb_rqueue_unlock(fbdev);
731 
732 	return r;
733 }
734 
omapfb_update_window_async(struct fb_info * fbi,struct omapfb_update_window * win,void (* callback)(void *),void * callback_data)735 int omapfb_update_window_async(struct fb_info *fbi,
736 				struct omapfb_update_window *win,
737 				void (*callback)(void *),
738 				void *callback_data)
739 {
740 	int xres, yres;
741 	struct omapfb_plane_struct *plane = fbi->par;
742 	struct omapfb_device *fbdev = plane->fbdev;
743 	struct fb_var_screeninfo *var = &fbi->var;
744 
745 	switch (var->rotate) {
746 	case 0:
747 	case 180:
748 		xres = fbdev->panel->x_res;
749 		yres = fbdev->panel->y_res;
750 		break;
751 	case 90:
752 	case 270:
753 		xres = fbdev->panel->y_res;
754 		yres = fbdev->panel->x_res;
755 		break;
756 	default:
757 		return -EINVAL;
758 	}
759 
760 	if (win->x >= xres || win->y >= yres ||
761 	    win->out_x > xres || win->out_y > yres)
762 		return -EINVAL;
763 
764 	if (!fbdev->ctrl->update_window ||
765 	    fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
766 		return -ENODEV;
767 
768 	if (win->x + win->width > xres)
769 		win->width = xres - win->x;
770 	if (win->y + win->height > yres)
771 		win->height = yres - win->y;
772 	if (win->out_x + win->out_width > xres)
773 		win->out_width = xres - win->out_x;
774 	if (win->out_y + win->out_height > yres)
775 		win->out_height = yres - win->out_y;
776 	if (!win->width || !win->height || !win->out_width || !win->out_height)
777 		return 0;
778 
779 	return fbdev->ctrl->update_window(fbi, win, callback, callback_data);
780 }
781 EXPORT_SYMBOL(omapfb_update_window_async);
782 
omapfb_update_win(struct fb_info * fbi,struct omapfb_update_window * win)783 static int omapfb_update_win(struct fb_info *fbi,
784 				struct omapfb_update_window *win)
785 {
786 	struct omapfb_plane_struct *plane = fbi->par;
787 	int ret;
788 
789 	omapfb_rqueue_lock(plane->fbdev);
790 	ret = omapfb_update_window_async(fbi, win, NULL, NULL);
791 	omapfb_rqueue_unlock(plane->fbdev);
792 
793 	return ret;
794 }
795 
omapfb_update_full_screen(struct fb_info * fbi)796 static int omapfb_update_full_screen(struct fb_info *fbi)
797 {
798 	struct omapfb_plane_struct *plane = fbi->par;
799 	struct omapfb_device *fbdev = plane->fbdev;
800 	struct omapfb_update_window win;
801 	int r;
802 
803 	if (!fbdev->ctrl->update_window ||
804 	    fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
805 		return -ENODEV;
806 
807 	win.x = 0;
808 	win.y = 0;
809 	win.width = fbi->var.xres;
810 	win.height = fbi->var.yres;
811 	win.out_x = 0;
812 	win.out_y = 0;
813 	win.out_width = fbi->var.xres;
814 	win.out_height = fbi->var.yres;
815 	win.format = 0;
816 
817 	omapfb_rqueue_lock(fbdev);
818 	r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL);
819 	omapfb_rqueue_unlock(fbdev);
820 
821 	return r;
822 }
823 
omapfb_setup_plane(struct fb_info * fbi,struct omapfb_plane_info * pi)824 static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
825 {
826 	struct omapfb_plane_struct *plane = fbi->par;
827 	struct omapfb_device *fbdev = plane->fbdev;
828 	struct lcd_panel *panel = fbdev->panel;
829 	struct omapfb_plane_info old_info;
830 	int r = 0;
831 
832 	if (pi->pos_x + pi->out_width > panel->x_res ||
833 	    pi->pos_y + pi->out_height > panel->y_res)
834 		return -EINVAL;
835 
836 	omapfb_rqueue_lock(fbdev);
837 	if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) {
838 		/*
839 		 * This plane's memory was freed, can't enable it
840 		 * until it's reallocated.
841 		 */
842 		r = -EINVAL;
843 		goto out;
844 	}
845 	old_info = plane->info;
846 	plane->info = *pi;
847 	if (pi->enabled) {
848 		r = ctrl_change_mode(fbi);
849 		if (r < 0) {
850 			plane->info = old_info;
851 			goto out;
852 		}
853 	}
854 	r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled);
855 	if (r < 0) {
856 		plane->info = old_info;
857 		goto out;
858 	}
859 out:
860 	omapfb_rqueue_unlock(fbdev);
861 	return r;
862 }
863 
omapfb_query_plane(struct fb_info * fbi,struct omapfb_plane_info * pi)864 static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
865 {
866 	struct omapfb_plane_struct *plane = fbi->par;
867 
868 	*pi = plane->info;
869 	return 0;
870 }
871 
omapfb_setup_mem(struct fb_info * fbi,struct omapfb_mem_info * mi)872 static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
873 {
874 	struct omapfb_plane_struct *plane = fbi->par;
875 	struct omapfb_device *fbdev = plane->fbdev;
876 	struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx];
877 	size_t size;
878 	int r = 0;
879 
880 	if (fbdev->ctrl->setup_mem == NULL)
881 		return -ENODEV;
882 	if (mi->type > OMAPFB_MEMTYPE_MAX)
883 		return -EINVAL;
884 
885 	size = PAGE_ALIGN(mi->size);
886 	omapfb_rqueue_lock(fbdev);
887 	if (plane->info.enabled) {
888 		r = -EBUSY;
889 		goto out;
890 	}
891 	if (rg->size != size || rg->type != mi->type) {
892 		struct fb_var_screeninfo *new_var = &fbdev->new_var;
893 		unsigned long old_size = rg->size;
894 		u8	      old_type = rg->type;
895 		unsigned long paddr;
896 
897 		rg->size = size;
898 		rg->type = mi->type;
899 		/*
900 		 * size == 0 is a special case, for which we
901 		 * don't check / adjust the screen parameters.
902 		 * This isn't a problem since the plane can't
903 		 * be reenabled unless its size is > 0.
904 		 */
905 		if (old_size != size && size) {
906 			if (size) {
907 				memcpy(new_var, &fbi->var, sizeof(*new_var));
908 				r = set_fb_var(fbi, new_var);
909 				if (r < 0)
910 					goto out;
911 			}
912 		}
913 
914 		if (fbdev->ctrl->sync)
915 			fbdev->ctrl->sync();
916 		r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr);
917 		if (r < 0) {
918 			/* Revert changes. */
919 			rg->size = old_size;
920 			rg->type = old_type;
921 			goto out;
922 		}
923 		rg->paddr = paddr;
924 
925 		if (old_size != size) {
926 			if (size) {
927 				memcpy(&fbi->var, new_var, sizeof(fbi->var));
928 				set_fb_fix(fbi, 0);
929 			} else {
930 				/*
931 				 * Set these explicitly to indicate that the
932 				 * plane memory is dealloce'd, the other
933 				 * screen parameters in var / fix are invalid.
934 				 */
935 				mutex_lock(&fbi->mm_lock);
936 				fbi->fix.smem_start = 0;
937 				fbi->fix.smem_len = 0;
938 				mutex_unlock(&fbi->mm_lock);
939 			}
940 		}
941 	}
942 out:
943 	omapfb_rqueue_unlock(fbdev);
944 
945 	return r;
946 }
947 
omapfb_query_mem(struct fb_info * fbi,struct omapfb_mem_info * mi)948 static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
949 {
950 	struct omapfb_plane_struct *plane = fbi->par;
951 	struct omapfb_device *fbdev = plane->fbdev;
952 	struct omapfb_mem_region *rg;
953 
954 	rg = &fbdev->mem_desc.region[plane->idx];
955 	memset(mi, 0, sizeof(*mi));
956 	mi->size = rg->size;
957 	mi->type = rg->type;
958 
959 	return 0;
960 }
961 
omapfb_set_color_key(struct omapfb_device * fbdev,struct omapfb_color_key * ck)962 static int omapfb_set_color_key(struct omapfb_device *fbdev,
963 				struct omapfb_color_key *ck)
964 {
965 	int r;
966 
967 	if (!fbdev->ctrl->set_color_key)
968 		return -ENODEV;
969 
970 	omapfb_rqueue_lock(fbdev);
971 	r = fbdev->ctrl->set_color_key(ck);
972 	omapfb_rqueue_unlock(fbdev);
973 
974 	return r;
975 }
976 
omapfb_get_color_key(struct omapfb_device * fbdev,struct omapfb_color_key * ck)977 static int omapfb_get_color_key(struct omapfb_device *fbdev,
978 				struct omapfb_color_key *ck)
979 {
980 	int r;
981 
982 	if (!fbdev->ctrl->get_color_key)
983 		return -ENODEV;
984 
985 	omapfb_rqueue_lock(fbdev);
986 	r = fbdev->ctrl->get_color_key(ck);
987 	omapfb_rqueue_unlock(fbdev);
988 
989 	return r;
990 }
991 
992 static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
993 static int notifier_inited;
994 
omapfb_init_notifier(void)995 static void omapfb_init_notifier(void)
996 {
997 	int i;
998 
999 	for (i = 0; i < OMAPFB_PLANE_NUM; i++)
1000 		BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]);
1001 }
1002 
omapfb_register_client(struct omapfb_notifier_block * omapfb_nb,omapfb_notifier_callback_t callback,void * callback_data)1003 int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
1004 				omapfb_notifier_callback_t callback,
1005 				void *callback_data)
1006 {
1007 	int r;
1008 
1009 	if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
1010 		return -EINVAL;
1011 
1012 	if (!notifier_inited) {
1013 		omapfb_init_notifier();
1014 		notifier_inited = 1;
1015 	}
1016 
1017 	omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
1018 					unsigned long, void *))callback;
1019 	omapfb_nb->data = callback_data;
1020 	r = blocking_notifier_chain_register(
1021 				&omapfb_client_list[omapfb_nb->plane_idx],
1022 				&omapfb_nb->nb);
1023 	if (r)
1024 		return r;
1025 	if (omapfb_dev != NULL &&
1026 	    omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
1027 		omapfb_dev->ctrl->bind_client(omapfb_nb);
1028 	}
1029 
1030 	return 0;
1031 }
1032 EXPORT_SYMBOL(omapfb_register_client);
1033 
omapfb_unregister_client(struct omapfb_notifier_block * omapfb_nb)1034 int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
1035 {
1036 	return blocking_notifier_chain_unregister(
1037 		&omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb);
1038 }
1039 EXPORT_SYMBOL(omapfb_unregister_client);
1040 
omapfb_notify_clients(struct omapfb_device * fbdev,unsigned long event)1041 void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
1042 {
1043 	int i;
1044 
1045 	if (!notifier_inited)
1046 		/* no client registered yet */
1047 		return;
1048 
1049 	for (i = 0; i < OMAPFB_PLANE_NUM; i++)
1050 		blocking_notifier_call_chain(&omapfb_client_list[i], event,
1051 				    fbdev->fb_info[i]);
1052 }
1053 EXPORT_SYMBOL(omapfb_notify_clients);
1054 
omapfb_set_update_mode(struct omapfb_device * fbdev,enum omapfb_update_mode mode)1055 static int omapfb_set_update_mode(struct omapfb_device *fbdev,
1056 				   enum omapfb_update_mode mode)
1057 {
1058 	int r;
1059 
1060 	omapfb_rqueue_lock(fbdev);
1061 	r = fbdev->ctrl->set_update_mode(mode);
1062 	omapfb_rqueue_unlock(fbdev);
1063 
1064 	return r;
1065 }
1066 
omapfb_get_update_mode(struct omapfb_device * fbdev)1067 static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
1068 {
1069 	int r;
1070 
1071 	omapfb_rqueue_lock(fbdev);
1072 	r = fbdev->ctrl->get_update_mode();
1073 	omapfb_rqueue_unlock(fbdev);
1074 
1075 	return r;
1076 }
1077 
omapfb_get_caps(struct omapfb_device * fbdev,int plane,struct omapfb_caps * caps)1078 static void omapfb_get_caps(struct omapfb_device *fbdev, int plane,
1079 				     struct omapfb_caps *caps)
1080 {
1081 	memset(caps, 0, sizeof(*caps));
1082 	fbdev->ctrl->get_caps(plane, caps);
1083 	caps->ctrl |= fbdev->panel->get_caps(fbdev->panel);
1084 }
1085 
1086 /* For lcd testing */
omapfb_write_first_pixel(struct omapfb_device * fbdev,u16 pixval)1087 void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
1088 {
1089 	omapfb_rqueue_lock(fbdev);
1090 	*(u16 *)fbdev->mem_desc.region[0].vaddr = pixval;
1091 	if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
1092 		struct omapfb_update_window win;
1093 
1094 		memset(&win, 0, sizeof(win));
1095 		win.width = 2;
1096 		win.height = 2;
1097 		win.out_width = 2;
1098 		win.out_height = 2;
1099 		fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL);
1100 	}
1101 	omapfb_rqueue_unlock(fbdev);
1102 }
1103 EXPORT_SYMBOL(omapfb_write_first_pixel);
1104 
1105 /*
1106  * Ioctl interface. Part of the kernel mode frame buffer API is duplicated
1107  * here to be accessible by user mode code.
1108  */
omapfb_ioctl(struct fb_info * fbi,unsigned int cmd,unsigned long arg)1109 static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
1110 			unsigned long arg)
1111 {
1112 	struct omapfb_plane_struct *plane = fbi->par;
1113 	struct omapfb_device	*fbdev = plane->fbdev;
1114 	struct fb_ops		*ops = fbi->fbops;
1115 	union {
1116 		struct omapfb_update_window	update_window;
1117 		struct omapfb_plane_info	plane_info;
1118 		struct omapfb_mem_info		mem_info;
1119 		struct omapfb_color_key		color_key;
1120 		enum omapfb_update_mode		update_mode;
1121 		struct omapfb_caps		caps;
1122 		unsigned int		mirror;
1123 		int			plane_out;
1124 		int			enable_plane;
1125 	} p;
1126 	int r = 0;
1127 
1128 	BUG_ON(!ops);
1129 	switch (cmd) {
1130 	case OMAPFB_MIRROR:
1131 		if (get_user(p.mirror, (int __user *)arg))
1132 			r = -EFAULT;
1133 		else
1134 			omapfb_mirror(fbi, p.mirror);
1135 		break;
1136 	case OMAPFB_SYNC_GFX:
1137 		omapfb_sync(fbi);
1138 		break;
1139 	case OMAPFB_VSYNC:
1140 		break;
1141 	case OMAPFB_SET_UPDATE_MODE:
1142 		if (get_user(p.update_mode, (int __user *)arg))
1143 			r = -EFAULT;
1144 		else
1145 			r = omapfb_set_update_mode(fbdev, p.update_mode);
1146 		break;
1147 	case OMAPFB_GET_UPDATE_MODE:
1148 		p.update_mode = omapfb_get_update_mode(fbdev);
1149 		if (put_user(p.update_mode,
1150 					(enum omapfb_update_mode __user *)arg))
1151 			r = -EFAULT;
1152 		break;
1153 	case OMAPFB_UPDATE_WINDOW_OLD:
1154 		if (copy_from_user(&p.update_window, (void __user *)arg,
1155 				   sizeof(struct omapfb_update_window_old)))
1156 			r = -EFAULT;
1157 		else {
1158 			struct omapfb_update_window *u = &p.update_window;
1159 			u->out_x = u->x;
1160 			u->out_y = u->y;
1161 			u->out_width = u->width;
1162 			u->out_height = u->height;
1163 			memset(u->reserved, 0, sizeof(u->reserved));
1164 			r = omapfb_update_win(fbi, u);
1165 		}
1166 		break;
1167 	case OMAPFB_UPDATE_WINDOW:
1168 		if (copy_from_user(&p.update_window, (void __user *)arg,
1169 				   sizeof(p.update_window)))
1170 			r = -EFAULT;
1171 		else
1172 			r = omapfb_update_win(fbi, &p.update_window);
1173 		break;
1174 	case OMAPFB_SETUP_PLANE:
1175 		if (copy_from_user(&p.plane_info, (void __user *)arg,
1176 				   sizeof(p.plane_info)))
1177 			r = -EFAULT;
1178 		else
1179 			r = omapfb_setup_plane(fbi, &p.plane_info);
1180 		break;
1181 	case OMAPFB_QUERY_PLANE:
1182 		if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0)
1183 			break;
1184 		if (copy_to_user((void __user *)arg, &p.plane_info,
1185 				   sizeof(p.plane_info)))
1186 			r = -EFAULT;
1187 		break;
1188 	case OMAPFB_SETUP_MEM:
1189 		if (copy_from_user(&p.mem_info, (void __user *)arg,
1190 				   sizeof(p.mem_info)))
1191 			r = -EFAULT;
1192 		else
1193 			r = omapfb_setup_mem(fbi, &p.mem_info);
1194 		break;
1195 	case OMAPFB_QUERY_MEM:
1196 		if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0)
1197 			break;
1198 		if (copy_to_user((void __user *)arg, &p.mem_info,
1199 				   sizeof(p.mem_info)))
1200 			r = -EFAULT;
1201 		break;
1202 	case OMAPFB_SET_COLOR_KEY:
1203 		if (copy_from_user(&p.color_key, (void __user *)arg,
1204 				   sizeof(p.color_key)))
1205 			r = -EFAULT;
1206 		else
1207 			r = omapfb_set_color_key(fbdev, &p.color_key);
1208 		break;
1209 	case OMAPFB_GET_COLOR_KEY:
1210 		if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0)
1211 			break;
1212 		if (copy_to_user((void __user *)arg, &p.color_key,
1213 				 sizeof(p.color_key)))
1214 			r = -EFAULT;
1215 		break;
1216 	case OMAPFB_GET_CAPS:
1217 		omapfb_get_caps(fbdev, plane->idx, &p.caps);
1218 		if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
1219 			r = -EFAULT;
1220 		break;
1221 	case OMAPFB_LCD_TEST:
1222 		{
1223 			int test_num;
1224 
1225 			if (get_user(test_num, (int __user *)arg)) {
1226 				r = -EFAULT;
1227 				break;
1228 			}
1229 			if (!fbdev->panel->run_test) {
1230 				r = -EINVAL;
1231 				break;
1232 			}
1233 			r = fbdev->panel->run_test(fbdev->panel, test_num);
1234 			break;
1235 		}
1236 	case OMAPFB_CTRL_TEST:
1237 		{
1238 			int test_num;
1239 
1240 			if (get_user(test_num, (int __user *)arg)) {
1241 				r = -EFAULT;
1242 				break;
1243 			}
1244 			if (!fbdev->ctrl->run_test) {
1245 				r = -EINVAL;
1246 				break;
1247 			}
1248 			r = fbdev->ctrl->run_test(test_num);
1249 			break;
1250 		}
1251 	default:
1252 		r = -EINVAL;
1253 	}
1254 
1255 	return r;
1256 }
1257 
omapfb_mmap(struct fb_info * info,struct vm_area_struct * vma)1258 static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
1259 {
1260 	struct omapfb_plane_struct *plane = info->par;
1261 	struct omapfb_device *fbdev = plane->fbdev;
1262 	int r;
1263 
1264 	omapfb_rqueue_lock(fbdev);
1265 	r = fbdev->ctrl->mmap(info, vma);
1266 	omapfb_rqueue_unlock(fbdev);
1267 
1268 	return r;
1269 }
1270 
1271 /*
1272  * Callback table for the frame buffer framework. Some of these pointers
1273  * will be changed according to the current setting of fb_info->accel_flags.
1274  */
1275 static struct fb_ops omapfb_ops = {
1276 	.owner		= THIS_MODULE,
1277 	.fb_open        = omapfb_open,
1278 	.fb_release     = omapfb_release,
1279 	.fb_setcolreg	= omapfb_setcolreg,
1280 	.fb_setcmap	= omapfb_setcmap,
1281 	.fb_fillrect	= cfb_fillrect,
1282 	.fb_copyarea	= cfb_copyarea,
1283 	.fb_imageblit	= cfb_imageblit,
1284 	.fb_blank       = omapfb_blank,
1285 	.fb_ioctl	= omapfb_ioctl,
1286 	.fb_check_var	= omapfb_check_var,
1287 	.fb_set_par	= omapfb_set_par,
1288 	.fb_rotate	= omapfb_rotate,
1289 	.fb_pan_display = omapfb_pan_display,
1290 };
1291 
1292 /*
1293  * ---------------------------------------------------------------------------
1294  * Sysfs interface
1295  * ---------------------------------------------------------------------------
1296  */
1297 /* omapfbX sysfs entries */
omapfb_show_caps_num(struct device * dev,struct device_attribute * attr,char * buf)1298 static ssize_t omapfb_show_caps_num(struct device *dev,
1299 				    struct device_attribute *attr, char *buf)
1300 {
1301 	struct omapfb_device *fbdev = dev_get_drvdata(dev);
1302 	int plane;
1303 	size_t size;
1304 	struct omapfb_caps caps;
1305 
1306 	plane = 0;
1307 	size = 0;
1308 	while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) {
1309 		omapfb_get_caps(fbdev, plane, &caps);
1310 		size += snprintf(&buf[size], PAGE_SIZE - size,
1311 			"plane#%d %#010x %#010x %#010x\n",
1312 			plane, caps.ctrl, caps.plane_color, caps.wnd_color);
1313 		plane++;
1314 	}
1315 	return size;
1316 }
1317 
omapfb_show_caps_text(struct device * dev,struct device_attribute * attr,char * buf)1318 static ssize_t omapfb_show_caps_text(struct device *dev,
1319 				     struct device_attribute *attr, char *buf)
1320 {
1321 	struct omapfb_device *fbdev = dev_get_drvdata(dev);
1322 	int i;
1323 	struct omapfb_caps caps;
1324 	int plane;
1325 	size_t size;
1326 
1327 	plane = 0;
1328 	size = 0;
1329 	while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) {
1330 		omapfb_get_caps(fbdev, plane, &caps);
1331 		size += snprintf(&buf[size], PAGE_SIZE - size,
1332 				 "plane#%d:\n", plane);
1333 		for (i = 0; i < ARRAY_SIZE(ctrl_caps) &&
1334 		     size < PAGE_SIZE; i++) {
1335 			if (ctrl_caps[i].flag & caps.ctrl)
1336 				size += snprintf(&buf[size], PAGE_SIZE - size,
1337 					" %s\n", ctrl_caps[i].name);
1338 		}
1339 		size += snprintf(&buf[size], PAGE_SIZE - size,
1340 				 " plane colors:\n");
1341 		for (i = 0; i < ARRAY_SIZE(color_caps) &&
1342 		     size < PAGE_SIZE; i++) {
1343 			if (color_caps[i].flag & caps.plane_color)
1344 				size += snprintf(&buf[size], PAGE_SIZE - size,
1345 					"  %s\n", color_caps[i].name);
1346 		}
1347 		size += snprintf(&buf[size], PAGE_SIZE - size,
1348 				 " window colors:\n");
1349 		for (i = 0; i < ARRAY_SIZE(color_caps) &&
1350 		     size < PAGE_SIZE; i++) {
1351 			if (color_caps[i].flag & caps.wnd_color)
1352 				size += snprintf(&buf[size], PAGE_SIZE - size,
1353 					"  %s\n", color_caps[i].name);
1354 		}
1355 
1356 		plane++;
1357 	}
1358 	return size;
1359 }
1360 
1361 static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
1362 static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
1363 
1364 /* panel sysfs entries */
omapfb_show_panel_name(struct device * dev,struct device_attribute * attr,char * buf)1365 static ssize_t omapfb_show_panel_name(struct device *dev,
1366 				      struct device_attribute *attr, char *buf)
1367 {
1368 	struct omapfb_device *fbdev = dev_get_drvdata(dev);
1369 
1370 	return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
1371 }
1372 
omapfb_show_bklight_level(struct device * dev,struct device_attribute * attr,char * buf)1373 static ssize_t omapfb_show_bklight_level(struct device *dev,
1374 					 struct device_attribute *attr,
1375 					 char *buf)
1376 {
1377 	struct omapfb_device *fbdev = dev_get_drvdata(dev);
1378 	int r;
1379 
1380 	if (fbdev->panel->get_bklight_level) {
1381 		r = snprintf(buf, PAGE_SIZE, "%d\n",
1382 			     fbdev->panel->get_bklight_level(fbdev->panel));
1383 	} else
1384 		r = -ENODEV;
1385 	return r;
1386 }
1387 
omapfb_store_bklight_level(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1388 static ssize_t omapfb_store_bklight_level(struct device *dev,
1389 					  struct device_attribute *attr,
1390 					  const char *buf, size_t size)
1391 {
1392 	struct omapfb_device *fbdev = dev_get_drvdata(dev);
1393 	int r;
1394 
1395 	if (fbdev->panel->set_bklight_level) {
1396 		unsigned int level;
1397 
1398 		if (sscanf(buf, "%10d", &level) == 1) {
1399 			r = fbdev->panel->set_bklight_level(fbdev->panel,
1400 							    level);
1401 		} else
1402 			r = -EINVAL;
1403 	} else
1404 		r = -ENODEV;
1405 	return r ? r : size;
1406 }
1407 
omapfb_show_bklight_max(struct device * dev,struct device_attribute * attr,char * buf)1408 static ssize_t omapfb_show_bklight_max(struct device *dev,
1409 				       struct device_attribute *attr, char *buf)
1410 {
1411 	struct omapfb_device *fbdev = dev_get_drvdata(dev);
1412 	int r;
1413 
1414 	if (fbdev->panel->get_bklight_level) {
1415 		r = snprintf(buf, PAGE_SIZE, "%d\n",
1416 			     fbdev->panel->get_bklight_max(fbdev->panel));
1417 	} else
1418 		r = -ENODEV;
1419 	return r;
1420 }
1421 
1422 static struct device_attribute dev_attr_panel_name =
1423 	__ATTR(name, 0444, omapfb_show_panel_name, NULL);
1424 static DEVICE_ATTR(backlight_level, 0664,
1425 		   omapfb_show_bklight_level, omapfb_store_bklight_level);
1426 static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
1427 
1428 static struct attribute *panel_attrs[] = {
1429 	&dev_attr_panel_name.attr,
1430 	&dev_attr_backlight_level.attr,
1431 	&dev_attr_backlight_max.attr,
1432 	NULL,
1433 };
1434 
1435 static struct attribute_group panel_attr_grp = {
1436 	.name  = "panel",
1437 	.attrs = panel_attrs,
1438 };
1439 
1440 /* ctrl sysfs entries */
omapfb_show_ctrl_name(struct device * dev,struct device_attribute * attr,char * buf)1441 static ssize_t omapfb_show_ctrl_name(struct device *dev,
1442 				     struct device_attribute *attr, char *buf)
1443 {
1444 	struct omapfb_device *fbdev = dev_get_drvdata(dev);
1445 
1446 	return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
1447 }
1448 
1449 static struct device_attribute dev_attr_ctrl_name =
1450 	__ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
1451 
1452 static struct attribute *ctrl_attrs[] = {
1453 	&dev_attr_ctrl_name.attr,
1454 	NULL,
1455 };
1456 
1457 static struct attribute_group ctrl_attr_grp = {
1458 	.name  = "ctrl",
1459 	.attrs = ctrl_attrs,
1460 };
1461 
omapfb_register_sysfs(struct omapfb_device * fbdev)1462 static int omapfb_register_sysfs(struct omapfb_device *fbdev)
1463 {
1464 	int r;
1465 
1466 	if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
1467 		goto fail0;
1468 
1469 	if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
1470 		goto fail1;
1471 
1472 	if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
1473 		goto fail2;
1474 
1475 	if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
1476 		goto fail3;
1477 
1478 	return 0;
1479 fail3:
1480 	sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1481 fail2:
1482 	device_remove_file(fbdev->dev, &dev_attr_caps_text);
1483 fail1:
1484 	device_remove_file(fbdev->dev, &dev_attr_caps_num);
1485 fail0:
1486 	dev_err(fbdev->dev, "unable to register sysfs interface\n");
1487 	return r;
1488 }
1489 
omapfb_unregister_sysfs(struct omapfb_device * fbdev)1490 static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
1491 {
1492 	sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
1493 	sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
1494 	device_remove_file(fbdev->dev, &dev_attr_caps_num);
1495 	device_remove_file(fbdev->dev, &dev_attr_caps_text);
1496 }
1497 
1498 /*
1499  * ---------------------------------------------------------------------------
1500  * LDM callbacks
1501  * ---------------------------------------------------------------------------
1502  */
1503 /* Initialize system fb_info object and set the default video mode.
1504  * The frame buffer memory already allocated by lcddma_init
1505  */
fbinfo_init(struct omapfb_device * fbdev,struct fb_info * info)1506 static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info)
1507 {
1508 	struct fb_var_screeninfo	*var = &info->var;
1509 	struct fb_fix_screeninfo	*fix = &info->fix;
1510 	int				r = 0;
1511 
1512 	info->fbops = &omapfb_ops;
1513 	info->flags = FBINFO_FLAG_DEFAULT;
1514 
1515 	strncpy(fix->id, MODULE_NAME, sizeof(fix->id));
1516 
1517 	info->pseudo_palette = fbdev->pseudo_palette;
1518 
1519 	var->accel_flags  = def_accel ? FB_ACCELF_TEXT : 0;
1520 	var->xres = def_vxres;
1521 	var->yres = def_vyres;
1522 	var->xres_virtual = def_vxres;
1523 	var->yres_virtual = def_vyres;
1524 	var->rotate	  = def_rotate;
1525 	var->bits_per_pixel = fbdev->panel->bpp;
1526 
1527 	set_fb_var(info, var);
1528 	set_fb_fix(info, 1);
1529 
1530 	r = fb_alloc_cmap(&info->cmap, 16, 0);
1531 	if (r != 0)
1532 		dev_err(fbdev->dev, "unable to allocate color map memory\n");
1533 
1534 	return r;
1535 }
1536 
1537 /* Release the fb_info object */
fbinfo_cleanup(struct omapfb_device * fbdev,struct fb_info * fbi)1538 static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
1539 {
1540 	fb_dealloc_cmap(&fbi->cmap);
1541 }
1542 
planes_cleanup(struct omapfb_device * fbdev)1543 static void planes_cleanup(struct omapfb_device *fbdev)
1544 {
1545 	int i;
1546 
1547 	for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1548 		if (fbdev->fb_info[i] == NULL)
1549 			break;
1550 		fbinfo_cleanup(fbdev, fbdev->fb_info[i]);
1551 		framebuffer_release(fbdev->fb_info[i]);
1552 	}
1553 }
1554 
planes_init(struct omapfb_device * fbdev)1555 static int planes_init(struct omapfb_device *fbdev)
1556 {
1557 	struct fb_info *fbi;
1558 	int i;
1559 	int r;
1560 
1561 	for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1562 		struct omapfb_plane_struct *plane;
1563 		fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct),
1564 					fbdev->dev);
1565 		if (fbi == NULL) {
1566 			dev_err(fbdev->dev,
1567 				"unable to allocate memory for plane info\n");
1568 			planes_cleanup(fbdev);
1569 			return -ENOMEM;
1570 		}
1571 		plane = fbi->par;
1572 		plane->idx = i;
1573 		plane->fbdev = fbdev;
1574 		plane->info.mirror = def_mirror;
1575 		fbdev->fb_info[i] = fbi;
1576 
1577 		if ((r = fbinfo_init(fbdev, fbi)) < 0) {
1578 			framebuffer_release(fbi);
1579 			planes_cleanup(fbdev);
1580 			return r;
1581 		}
1582 		plane->info.out_width = fbi->var.xres;
1583 		plane->info.out_height = fbi->var.yres;
1584 	}
1585 	return 0;
1586 }
1587 
1588 /*
1589  * Free driver resources. Can be called to rollback an aborted initialization
1590  * sequence.
1591  */
omapfb_free_resources(struct omapfb_device * fbdev,int state)1592 static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
1593 {
1594 	int i;
1595 
1596 	switch (state) {
1597 	case OMAPFB_ACTIVE:
1598 		for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
1599 			unregister_framebuffer(fbdev->fb_info[i]);
1600 	case 7:
1601 		omapfb_unregister_sysfs(fbdev);
1602 	case 6:
1603 		fbdev->panel->disable(fbdev->panel);
1604 	case 5:
1605 		omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
1606 	case 4:
1607 		planes_cleanup(fbdev);
1608 	case 3:
1609 		ctrl_cleanup(fbdev);
1610 	case 2:
1611 		fbdev->panel->cleanup(fbdev->panel);
1612 	case 1:
1613 		dev_set_drvdata(fbdev->dev, NULL);
1614 		kfree(fbdev);
1615 	case 0:
1616 		/* nothing to free */
1617 		break;
1618 	default:
1619 		BUG();
1620 	}
1621 }
1622 
omapfb_find_ctrl(struct omapfb_device * fbdev)1623 static int omapfb_find_ctrl(struct omapfb_device *fbdev)
1624 {
1625 	struct omapfb_platform_data *conf;
1626 	char name[17];
1627 	int i;
1628 
1629 	conf = fbdev->dev->platform_data;
1630 
1631 	fbdev->ctrl = NULL;
1632 
1633 	strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
1634 	name[sizeof(name) - 1] = '\0';
1635 
1636 	if (strcmp(name, "internal") == 0) {
1637 		fbdev->ctrl = fbdev->int_ctrl;
1638 		return 0;
1639 	}
1640 
1641 	for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
1642 		dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name);
1643 		if (strcmp(ctrls[i]->name, name) == 0) {
1644 			fbdev->ctrl = ctrls[i];
1645 			break;
1646 		}
1647 	}
1648 
1649 	if (fbdev->ctrl == NULL) {
1650 		dev_dbg(fbdev->dev, "ctrl %s not supported\n", name);
1651 		return -1;
1652 	}
1653 
1654 	return 0;
1655 }
1656 
check_required_callbacks(struct omapfb_device * fbdev)1657 static void check_required_callbacks(struct omapfb_device *fbdev)
1658 {
1659 #define _C(x) (fbdev->ctrl->x != NULL)
1660 #define _P(x) (fbdev->panel->x != NULL)
1661 	BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
1662 	BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
1663 		 _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
1664 		 _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
1665 		 _P(get_caps)));
1666 #undef _P
1667 #undef _C
1668 }
1669 
1670 /*
1671  * Called by LDM binding to probe and attach a new device.
1672  * Initialization sequence:
1673  *   1. allocate system omapfb_device structure
1674  *   2. select controller type according to platform configuration
1675  *      init LCD panel
1676  *   3. init LCD controller and LCD DMA
1677  *   4. init system fb_info structure for all planes
1678  *   5. setup video mode for first plane and enable it
1679  *   6. enable LCD panel
1680  *   7. register sysfs attributes
1681  *   OMAPFB_ACTIVE: register system fb_info structure for all planes
1682  */
omapfb_do_probe(struct platform_device * pdev,struct lcd_panel * panel)1683 static int omapfb_do_probe(struct platform_device *pdev,
1684 				struct lcd_panel *panel)
1685 {
1686 	struct omapfb_device	*fbdev = NULL;
1687 	int			init_state;
1688 	unsigned long		phz, hhz, vhz;
1689 	unsigned long		vram;
1690 	int			i;
1691 	int			r = 0;
1692 
1693 	init_state = 0;
1694 
1695 	if (pdev->num_resources != 0) {
1696 		dev_err(&pdev->dev, "probed for an unknown device\n");
1697 		r = -ENODEV;
1698 		goto cleanup;
1699 	}
1700 
1701 	if (pdev->dev.platform_data == NULL) {
1702 		dev_err(&pdev->dev, "missing platform data\n");
1703 		r = -ENOENT;
1704 		goto cleanup;
1705 	}
1706 
1707 	fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL);
1708 	if (fbdev == NULL) {
1709 		dev_err(&pdev->dev,
1710 			"unable to allocate memory for device info\n");
1711 		r = -ENOMEM;
1712 		goto cleanup;
1713 	}
1714 	init_state++;
1715 
1716 	fbdev->dev = &pdev->dev;
1717 	fbdev->panel = panel;
1718 	fbdev->dssdev = &omapdss_device;
1719 	platform_set_drvdata(pdev, fbdev);
1720 
1721 	mutex_init(&fbdev->rqueue_mutex);
1722 
1723 #ifdef CONFIG_ARCH_OMAP1
1724 	fbdev->int_ctrl = &omap1_int_ctrl;
1725 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1726 	fbdev->ext_if = &omap1_ext_if;
1727 #endif
1728 #else	/* OMAP2 */
1729 	fbdev->int_ctrl = &omap2_int_ctrl;
1730 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
1731 	fbdev->ext_if = &omap2_ext_if;
1732 #endif
1733 #endif
1734 	if (omapfb_find_ctrl(fbdev) < 0) {
1735 		dev_err(fbdev->dev,
1736 			"LCD controller not found, board not supported\n");
1737 		r = -ENODEV;
1738 		goto cleanup;
1739 	}
1740 
1741 	r = fbdev->panel->init(fbdev->panel, fbdev);
1742 	if (r)
1743 		goto cleanup;
1744 
1745 	pr_info("omapfb: configured for panel %s\n", fbdev->panel->name);
1746 
1747 	def_vxres = def_vxres ? def_vxres : fbdev->panel->x_res;
1748 	def_vyres = def_vyres ? def_vyres : fbdev->panel->y_res;
1749 
1750 	init_state++;
1751 
1752 	r = ctrl_init(fbdev);
1753 	if (r)
1754 		goto cleanup;
1755 	if (fbdev->ctrl->mmap != NULL)
1756 		omapfb_ops.fb_mmap = omapfb_mmap;
1757 	init_state++;
1758 
1759 	check_required_callbacks(fbdev);
1760 
1761 	r = planes_init(fbdev);
1762 	if (r)
1763 		goto cleanup;
1764 	init_state++;
1765 
1766 #ifdef CONFIG_FB_OMAP_DMA_TUNE
1767 	/* Set DMA priority for EMIFF access to highest */
1768 	if (cpu_class_is_omap1())
1769 		omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15);
1770 #endif
1771 
1772 	r = ctrl_change_mode(fbdev->fb_info[0]);
1773 	if (r) {
1774 		dev_err(fbdev->dev, "mode setting failed\n");
1775 		goto cleanup;
1776 	}
1777 
1778 	/* GFX plane is enabled by default */
1779 	r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
1780 	if (r)
1781 		goto cleanup;
1782 
1783 	omapfb_set_update_mode(fbdev, manual_update ?
1784 				   OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
1785 	init_state++;
1786 
1787 	r = fbdev->panel->enable(fbdev->panel);
1788 	if (r)
1789 		goto cleanup;
1790 	init_state++;
1791 
1792 	r = omapfb_register_sysfs(fbdev);
1793 	if (r)
1794 		goto cleanup;
1795 	init_state++;
1796 
1797 	vram = 0;
1798 	for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
1799 		r = register_framebuffer(fbdev->fb_info[i]);
1800 		if (r != 0) {
1801 			dev_err(fbdev->dev,
1802 				"registering framebuffer %d failed\n", i);
1803 			goto cleanup;
1804 		}
1805 		vram += fbdev->mem_desc.region[i].size;
1806 	}
1807 
1808 	fbdev->state = OMAPFB_ACTIVE;
1809 
1810 	panel = fbdev->panel;
1811 	phz = panel->pixel_clock * 1000;
1812 	hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
1813 	vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
1814 
1815 	omapfb_dev = fbdev;
1816 
1817 	pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n",
1818 			vram, fbdev->mem_desc.region_cnt);
1819 	pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz "
1820 			"vfreq %lu.%lu Hz\n",
1821 			phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
1822 
1823 	return 0;
1824 
1825 cleanup:
1826 	omapfb_free_resources(fbdev, init_state);
1827 
1828 	return r;
1829 }
1830 
omapfb_probe(struct platform_device * pdev)1831 static int omapfb_probe(struct platform_device *pdev)
1832 {
1833 	int r;
1834 
1835 	BUG_ON(fbdev_pdev != NULL);
1836 
1837 	r = platform_device_register(&omapdss_device);
1838 	if (r) {
1839 		dev_err(&pdev->dev, "can't register omapdss device\n");
1840 		return r;
1841 	}
1842 
1843 	/* Delay actual initialization until the LCD is registered */
1844 	fbdev_pdev = pdev;
1845 	if (fbdev_panel != NULL)
1846 		omapfb_do_probe(fbdev_pdev, fbdev_panel);
1847 	return 0;
1848 }
1849 
omapfb_register_panel(struct lcd_panel * panel)1850 void omapfb_register_panel(struct lcd_panel *panel)
1851 {
1852 	BUG_ON(fbdev_panel != NULL);
1853 
1854 	fbdev_panel = panel;
1855 	if (fbdev_pdev != NULL)
1856 		omapfb_do_probe(fbdev_pdev, fbdev_panel);
1857 }
1858 
1859 /* Called when the device is being detached from the driver */
omapfb_remove(struct platform_device * pdev)1860 static int omapfb_remove(struct platform_device *pdev)
1861 {
1862 	struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1863 	enum omapfb_state saved_state = fbdev->state;
1864 
1865 	/* FIXME: wait till completion of pending events */
1866 
1867 	fbdev->state = OMAPFB_DISABLED;
1868 	omapfb_free_resources(fbdev, saved_state);
1869 
1870 	platform_device_unregister(&omapdss_device);
1871 	fbdev->dssdev = NULL;
1872 
1873 	return 0;
1874 }
1875 
1876 /* PM suspend */
omapfb_suspend(struct platform_device * pdev,pm_message_t mesg)1877 static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
1878 {
1879 	struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1880 
1881 	if (fbdev != NULL)
1882 		omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]);
1883 	return 0;
1884 }
1885 
1886 /* PM resume */
omapfb_resume(struct platform_device * pdev)1887 static int omapfb_resume(struct platform_device *pdev)
1888 {
1889 	struct omapfb_device *fbdev = platform_get_drvdata(pdev);
1890 
1891 	if (fbdev != NULL)
1892 		omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]);
1893 	return 0;
1894 }
1895 
1896 static struct platform_driver omapfb_driver = {
1897 	.probe		= omapfb_probe,
1898 	.remove		= omapfb_remove,
1899 	.suspend	= omapfb_suspend,
1900 	.resume		= omapfb_resume,
1901 	.driver		= {
1902 		.name	= MODULE_NAME,
1903 		.owner	= THIS_MODULE,
1904 	},
1905 };
1906 
1907 #ifndef MODULE
1908 
1909 /* Process kernel command line parameters */
omapfb_setup(char * options)1910 static int __init omapfb_setup(char *options)
1911 {
1912 	char *this_opt = NULL;
1913 	int r = 0;
1914 
1915 	pr_debug("omapfb: options %s\n", options);
1916 
1917 	if (!options || !*options)
1918 		return 0;
1919 
1920 	while (!r && (this_opt = strsep(&options, ",")) != NULL) {
1921 		if (!strncmp(this_opt, "accel", 5))
1922 			def_accel = 1;
1923 		else if (!strncmp(this_opt, "vram:", 5)) {
1924 			char *suffix;
1925 			unsigned long vram;
1926 			vram = (simple_strtoul(this_opt + 5, &suffix, 0));
1927 			switch (suffix[0]) {
1928 			case '\0':
1929 				break;
1930 			case 'm':
1931 			case 'M':
1932 				vram *= 1024;
1933 				/* Fall through */
1934 			case 'k':
1935 			case 'K':
1936 				vram *= 1024;
1937 				break;
1938 			default:
1939 				pr_debug("omapfb: invalid vram suffix %c\n",
1940 					 suffix[0]);
1941 				r = -1;
1942 			}
1943 			def_vram[def_vram_cnt++] = vram;
1944 		}
1945 		else if (!strncmp(this_opt, "vxres:", 6))
1946 			def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
1947 		else if (!strncmp(this_opt, "vyres:", 6))
1948 			def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
1949 		else if (!strncmp(this_opt, "rotate:", 7))
1950 			def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
1951 		else if (!strncmp(this_opt, "mirror:", 7))
1952 			def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
1953 		else if (!strncmp(this_opt, "manual_update", 13))
1954 			manual_update = 1;
1955 		else {
1956 			pr_debug("omapfb: invalid option\n");
1957 			r = -1;
1958 		}
1959 	}
1960 
1961 	return r;
1962 }
1963 
1964 #endif
1965 
1966 /* Register both the driver and the device */
omapfb_init(void)1967 static int __init omapfb_init(void)
1968 {
1969 #ifndef MODULE
1970 	char *option;
1971 
1972 	if (fb_get_options("omapfb", &option))
1973 		return -ENODEV;
1974 	omapfb_setup(option);
1975 #endif
1976 	/* Register the driver with LDM */
1977 	if (platform_driver_register(&omapfb_driver)) {
1978 		pr_debug("failed to register omapfb driver\n");
1979 		return -ENODEV;
1980 	}
1981 
1982 	return 0;
1983 }
1984 
omapfb_cleanup(void)1985 static void __exit omapfb_cleanup(void)
1986 {
1987 	platform_driver_unregister(&omapfb_driver);
1988 }
1989 
1990 module_param_named(accel, def_accel, uint, 0664);
1991 module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
1992 module_param_named(vxres, def_vxres, long, 0664);
1993 module_param_named(vyres, def_vyres, long, 0664);
1994 module_param_named(rotate, def_rotate, uint, 0664);
1995 module_param_named(mirror, def_mirror, uint, 0664);
1996 module_param_named(manual_update, manual_update, bool, 0664);
1997 
1998 module_init(omapfb_init);
1999 module_exit(omapfb_cleanup);
2000 
2001 MODULE_DESCRIPTION("TI OMAP framebuffer driver");
2002 MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
2003 MODULE_LICENSE("GPL");
2004