• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/video/
1/*
2 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
3 *
4 *  Freescale DIU Frame Buffer device driver
5 *
6 *  Authors: Hongjun Chen <hong-jun.chen@freescale.com>
7 *           Paul Widmer <paul.widmer@freescale.com>
8 *           Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
9 *           York Sun <yorksun@freescale.com>
10 *
11 *   Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
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 */
19
20#include <linux/module.h>
21#include <linux/kernel.h>
22#include <linux/errno.h>
23#include <linux/string.h>
24#include <linux/slab.h>
25#include <linux/fb.h>
26#include <linux/init.h>
27#include <linux/dma-mapping.h>
28#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/clk.h>
31#include <linux/uaccess.h>
32#include <linux/vmalloc.h>
33
34#include <linux/of_platform.h>
35
36#include <sysdev/fsl_soc.h>
37#include <linux/fsl-diu-fb.h>
38#include "edid.h"
39
40static struct fb_videomode __devinitdata fsl_diu_default_mode = {
41	.refresh	= 60,
42	.xres		= 1024,
43	.yres		= 768,
44	.pixclock	= 15385,
45	.left_margin	= 160,
46	.right_margin	= 24,
47	.upper_margin	= 29,
48	.lower_margin	= 3,
49	.hsync_len	= 136,
50	.vsync_len	= 6,
51	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
52	.vmode		= FB_VMODE_NONINTERLACED
53};
54
55static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
56	{
57		.name		= "1024x768-60",
58		.refresh	= 60,
59		.xres		= 1024,
60		.yres		= 768,
61		.pixclock	= 15385,
62		.left_margin	= 160,
63		.right_margin	= 24,
64		.upper_margin	= 29,
65		.lower_margin	= 3,
66		.hsync_len	= 136,
67		.vsync_len	= 6,
68		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
69		.vmode		= FB_VMODE_NONINTERLACED
70	},
71	{
72		.name		= "1024x768-70",
73		.refresh	= 70,
74		.xres		= 1024,
75		.yres		= 768,
76		.pixclock	= 16886,
77		.left_margin	= 3,
78		.right_margin	= 3,
79		.upper_margin	= 2,
80		.lower_margin	= 2,
81		.hsync_len	= 40,
82		.vsync_len	= 18,
83		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
84		.vmode		= FB_VMODE_NONINTERLACED
85	},
86	{
87		.name		= "1024x768-75",
88		.refresh	= 75,
89		.xres		= 1024,
90		.yres		= 768,
91		.pixclock	= 15009,
92		.left_margin	= 3,
93		.right_margin	= 3,
94		.upper_margin	= 2,
95		.lower_margin	= 2,
96		.hsync_len	= 80,
97		.vsync_len	= 32,
98		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
99		.vmode		= FB_VMODE_NONINTERLACED
100	},
101	{
102		.name		= "1280x1024-60",
103		.refresh	= 60,
104		.xres		= 1280,
105		.yres		= 1024,
106		.pixclock	= 9375,
107		.left_margin	= 38,
108		.right_margin	= 128,
109		.upper_margin	= 2,
110		.lower_margin	= 7,
111		.hsync_len	= 216,
112		.vsync_len	= 37,
113		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
114		.vmode		= FB_VMODE_NONINTERLACED
115	},
116	{
117		.name		= "1280x1024-70",
118		.refresh	= 70,
119		.xres		= 1280,
120		.yres		= 1024,
121		.pixclock	= 9380,
122		.left_margin	= 6,
123		.right_margin	= 6,
124		.upper_margin	= 4,
125		.lower_margin	= 4,
126		.hsync_len	= 60,
127		.vsync_len	= 94,
128		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
129		.vmode		= FB_VMODE_NONINTERLACED
130	},
131	{
132		.name		= "1280x1024-75",
133		.refresh	= 75,
134		.xres		= 1280,
135		.yres		= 1024,
136		.pixclock	= 9380,
137		.left_margin	= 6,
138		.right_margin	= 6,
139		.upper_margin	= 4,
140		.lower_margin	= 4,
141		.hsync_len	= 60,
142		.vsync_len	= 15,
143		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
144		.vmode		= FB_VMODE_NONINTERLACED
145	},
146	{
147		.name		= "320x240",		/* for AOI only */
148		.refresh	= 60,
149		.xres		= 320,
150		.yres		= 240,
151		.pixclock	= 15385,
152		.left_margin	= 0,
153		.right_margin	= 0,
154		.upper_margin	= 0,
155		.lower_margin	= 0,
156		.hsync_len	= 0,
157		.vsync_len	= 0,
158		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
159		.vmode		= FB_VMODE_NONINTERLACED
160	},
161	{
162		.name		= "1280x480-60",
163		.refresh	= 60,
164		.xres		= 1280,
165		.yres		= 480,
166		.pixclock	= 18939,
167		.left_margin	= 353,
168		.right_margin	= 47,
169		.upper_margin	= 39,
170		.lower_margin	= 4,
171		.hsync_len	= 8,
172		.vsync_len	= 2,
173		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
174		.vmode		= FB_VMODE_NONINTERLACED
175	},
176};
177
178static char *fb_mode = "1024x768-32@60";
179static unsigned long default_bpp = 32;
180static int monitor_port;
181
182#if defined(CONFIG_NOT_COHERENT_CACHE)
183static u8 *coherence_data;
184static size_t coherence_data_size;
185static unsigned int d_cache_line_size;
186#endif
187
188static DEFINE_SPINLOCK(diu_lock);
189
190struct fsl_diu_data {
191	struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];
192				/*FSL_AOI_NUM has one dummy AOI */
193	struct device_attribute dev_attr;
194	struct diu_ad *dummy_ad;
195	void *dummy_aoi_virt;
196	unsigned int irq;
197	int fb_enabled;
198	int monitor_port;
199};
200
201struct mfb_info {
202	int index;
203	int type;
204	char *id;
205	int registered;
206	int blank;
207	unsigned long pseudo_palette[16];
208	struct diu_ad *ad;
209	int cursor_reset;
210	unsigned char g_alpha;
211	unsigned int count;
212	int x_aoi_d;		/* aoi display x offset to physical screen */
213	int y_aoi_d;		/* aoi display y offset to physical screen */
214	struct fsl_diu_data *parent;
215	u8 *edid_data;
216};
217
218
219static struct mfb_info mfb_template[] = {
220	{		/* AOI 0 for plane 0 */
221	.index = 0,
222	.type = MFB_TYPE_OUTPUT,
223	.id = "Panel0",
224	.registered = 0,
225	.count = 0,
226	.x_aoi_d = 0,
227	.y_aoi_d = 0,
228	},
229	{		/* AOI 0 for plane 1 */
230	.index = 1,
231	.type = MFB_TYPE_OUTPUT,
232	.id = "Panel1 AOI0",
233	.registered = 0,
234	.g_alpha = 0xff,
235	.count = 0,
236	.x_aoi_d = 0,
237	.y_aoi_d = 0,
238	},
239	{		/* AOI 1 for plane 1 */
240	.index = 2,
241	.type = MFB_TYPE_OUTPUT,
242	.id = "Panel1 AOI1",
243	.registered = 0,
244	.g_alpha = 0xff,
245	.count = 0,
246	.x_aoi_d = 0,
247	.y_aoi_d = 480,
248	},
249	{		/* AOI 0 for plane 2 */
250	.index = 3,
251	.type = MFB_TYPE_OUTPUT,
252	.id = "Panel2 AOI0",
253	.registered = 0,
254	.g_alpha = 0xff,
255	.count = 0,
256	.x_aoi_d = 640,
257	.y_aoi_d = 0,
258	},
259	{		/* AOI 1 for plane 2 */
260	.index = 4,
261	.type = MFB_TYPE_OUTPUT,
262	.id = "Panel2 AOI1",
263	.registered = 0,
264	.g_alpha = 0xff,
265	.count = 0,
266	.x_aoi_d = 640,
267	.y_aoi_d = 480,
268	},
269};
270
271static struct diu_hw dr = {
272	.mode = MFB_MODE1,
273	.reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock),
274};
275
276static struct diu_pool pool;
277
278/**
279 * fsl_diu_alloc - allocate memory for the DIU
280 * @size: number of bytes to allocate
281 * @param: returned physical address of memory
282 *
283 * This function allocates a physically-contiguous block of memory.
284 */
285static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
286{
287	void *virt;
288
289	pr_debug("size=%zu\n", size);
290
291	virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);
292	if (virt) {
293		*phys = virt_to_phys(virt);
294		pr_debug("virt=%p phys=%llx\n", virt,
295			(unsigned long long)*phys);
296	}
297
298	return virt;
299}
300
301/**
302 * fsl_diu_free - release DIU memory
303 * @virt: pointer returned by fsl_diu_alloc()
304 * @size: number of bytes allocated by fsl_diu_alloc()
305 *
306 * This function releases memory allocated by fsl_diu_alloc().
307 */
308static void fsl_diu_free(void *virt, size_t size)
309{
310	pr_debug("virt=%p size=%zu\n", virt, size);
311
312	if (virt && size)
313		free_pages_exact(virt, size);
314}
315
316void wr_reg_wa(u32 *reg, u32 val)
317{
318	do {
319		out_be32(reg, val);
320	} while (in_be32(reg) != val);
321}
322
323static int fsl_diu_enable_panel(struct fb_info *info)
324{
325	struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
326	struct diu *hw = dr.diu_reg;
327	struct diu_ad *ad = mfbi->ad;
328	struct fsl_diu_data *machine_data = mfbi->parent;
329	int res = 0;
330
331	pr_debug("enable_panel index %d\n", mfbi->index);
332	if (mfbi->type != MFB_TYPE_OFF) {
333		switch (mfbi->index) {
334		case 0:				/* plane 0 */
335			if (hw->desc[0] != ad->paddr)
336				wr_reg_wa(&hw->desc[0], ad->paddr);
337			break;
338		case 1:				/* plane 1 AOI 0 */
339			cmfbi = machine_data->fsl_diu_info[2]->par;
340			if (hw->desc[1] != ad->paddr) {	/* AOI0 closed */
341				if (cmfbi->count > 0)	/* AOI1 open */
342					ad->next_ad =
343						cpu_to_le32(cmfbi->ad->paddr);
344				else
345					ad->next_ad = 0;
346				wr_reg_wa(&hw->desc[1], ad->paddr);
347			}
348			break;
349		case 3:				/* plane 2 AOI 0 */
350			cmfbi = machine_data->fsl_diu_info[4]->par;
351			if (hw->desc[2] != ad->paddr) {	/* AOI0 closed */
352				if (cmfbi->count > 0)	/* AOI1 open */
353					ad->next_ad =
354						cpu_to_le32(cmfbi->ad->paddr);
355				else
356					ad->next_ad = 0;
357				wr_reg_wa(&hw->desc[2], ad->paddr);
358			}
359			break;
360		case 2:				/* plane 1 AOI 1 */
361			pmfbi = machine_data->fsl_diu_info[1]->par;
362			ad->next_ad = 0;
363			if (hw->desc[1] == machine_data->dummy_ad->paddr)
364				wr_reg_wa(&hw->desc[1], ad->paddr);
365			else					/* AOI0 open */
366				pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
367			break;
368		case 4:				/* plane 2 AOI 1 */
369			pmfbi = machine_data->fsl_diu_info[3]->par;
370			ad->next_ad = 0;
371			if (hw->desc[2] == machine_data->dummy_ad->paddr)
372				wr_reg_wa(&hw->desc[2], ad->paddr);
373			else				/* AOI0 was open */
374				pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
375			break;
376		default:
377			res = -EINVAL;
378			break;
379		}
380	} else
381		res = -EINVAL;
382	return res;
383}
384
385static int fsl_diu_disable_panel(struct fb_info *info)
386{
387	struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
388	struct diu *hw = dr.diu_reg;
389	struct diu_ad *ad = mfbi->ad;
390	struct fsl_diu_data *machine_data = mfbi->parent;
391	int res = 0;
392
393	switch (mfbi->index) {
394	case 0:					/* plane 0 */
395		if (hw->desc[0] != machine_data->dummy_ad->paddr)
396			wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr);
397		break;
398	case 1:					/* plane 1 AOI 0 */
399		cmfbi = machine_data->fsl_diu_info[2]->par;
400		if (cmfbi->count > 0)	/* AOI1 is open */
401			wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
402					/* move AOI1 to the first */
403		else			/* AOI1 was closed */
404			wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
405					/* close AOI 0 */
406		break;
407	case 3:					/* plane 2 AOI 0 */
408		cmfbi = machine_data->fsl_diu_info[4]->par;
409		if (cmfbi->count > 0)	/* AOI1 is open */
410			wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
411					/* move AOI1 to the first */
412		else			/* AOI1 was closed */
413			wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
414					/* close AOI 0 */
415		break;
416	case 2:					/* plane 1 AOI 1 */
417		pmfbi = machine_data->fsl_diu_info[1]->par;
418		if (hw->desc[1] != ad->paddr) {
419				/* AOI1 is not the first in the chain */
420			if (pmfbi->count > 0)
421					/* AOI0 is open, must be the first */
422				pmfbi->ad->next_ad = 0;
423		} else			/* AOI1 is the first in the chain */
424			wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
425					/* close AOI 1 */
426		break;
427	case 4:					/* plane 2 AOI 1 */
428		pmfbi = machine_data->fsl_diu_info[3]->par;
429		if (hw->desc[2] != ad->paddr) {
430				/* AOI1 is not the first in the chain */
431			if (pmfbi->count > 0)
432				/* AOI0 is open, must be the first */
433				pmfbi->ad->next_ad = 0;
434		} else		/* AOI1 is the first in the chain */
435			wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
436				/* close AOI 1 */
437		break;
438	default:
439		res = -EINVAL;
440		break;
441	}
442
443	return res;
444}
445
446static void enable_lcdc(struct fb_info *info)
447{
448	struct diu *hw = dr.diu_reg;
449	struct mfb_info *mfbi = info->par;
450	struct fsl_diu_data *machine_data = mfbi->parent;
451
452	if (!machine_data->fb_enabled) {
453		out_be32(&hw->diu_mode, dr.mode);
454		machine_data->fb_enabled++;
455	}
456}
457
458static void disable_lcdc(struct fb_info *info)
459{
460	struct diu *hw = dr.diu_reg;
461	struct mfb_info *mfbi = info->par;
462	struct fsl_diu_data *machine_data = mfbi->parent;
463
464	if (machine_data->fb_enabled) {
465		out_be32(&hw->diu_mode, 0);
466		machine_data->fb_enabled = 0;
467	}
468}
469
470static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
471				struct fb_info *info)
472{
473	struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
474	struct fsl_diu_data *machine_data = mfbi->parent;
475	int available_height, upper_aoi_bottom, index = mfbi->index;
476	int lower_aoi_is_open, upper_aoi_is_open;
477	__u32 base_plane_width, base_plane_height, upper_aoi_height;
478
479	base_plane_width = machine_data->fsl_diu_info[0]->var.xres;
480	base_plane_height = machine_data->fsl_diu_info[0]->var.yres;
481
482	if (mfbi->x_aoi_d < 0)
483		mfbi->x_aoi_d = 0;
484	if (mfbi->y_aoi_d < 0)
485		mfbi->y_aoi_d = 0;
486	switch (index) {
487	case 0:
488		if (mfbi->x_aoi_d != 0)
489			mfbi->x_aoi_d = 0;
490		if (mfbi->y_aoi_d != 0)
491			mfbi->y_aoi_d = 0;
492		break;
493	case 1:			/* AOI 0 */
494	case 3:
495		lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;
496		lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
497		if (var->xres > base_plane_width)
498			var->xres = base_plane_width;
499		if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
500			mfbi->x_aoi_d = base_plane_width - var->xres;
501
502		if (lower_aoi_is_open)
503			available_height = lower_aoi_mfbi->y_aoi_d;
504		else
505			available_height = base_plane_height;
506		if (var->yres > available_height)
507			var->yres = available_height;
508		if ((mfbi->y_aoi_d + var->yres) > available_height)
509			mfbi->y_aoi_d = available_height - var->yres;
510		break;
511	case 2:			/* AOI 1 */
512	case 4:
513		upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;
514		upper_aoi_height =
515				machine_data->fsl_diu_info[index-1]->var.yres;
516		upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
517		upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
518		if (var->xres > base_plane_width)
519			var->xres = base_plane_width;
520		if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
521			mfbi->x_aoi_d = base_plane_width - var->xres;
522		if (mfbi->y_aoi_d < 0)
523			mfbi->y_aoi_d = 0;
524		if (upper_aoi_is_open) {
525			if (mfbi->y_aoi_d < upper_aoi_bottom)
526				mfbi->y_aoi_d = upper_aoi_bottom;
527			available_height = base_plane_height
528						- upper_aoi_bottom;
529		} else
530			available_height = base_plane_height;
531		if (var->yres > available_height)
532			var->yres = available_height;
533		if ((mfbi->y_aoi_d + var->yres) > base_plane_height)
534			mfbi->y_aoi_d = base_plane_height - var->yres;
535		break;
536	}
537}
538/*
539 * Checks to see if the hardware supports the state requested by var passed
540 * in. This function does not alter the hardware state! If the var passed in
541 * is slightly off by what the hardware can support then we alter the var
542 * PASSED in to what we can do. If the hardware doesn't support mode change
543 * a -EINVAL will be returned by the upper layers.
544 */
545static int fsl_diu_check_var(struct fb_var_screeninfo *var,
546				struct fb_info *info)
547{
548	unsigned long htotal, vtotal;
549
550	pr_debug("check_var xres: %d\n", var->xres);
551	pr_debug("check_var yres: %d\n", var->yres);
552
553	if (var->xres_virtual < var->xres)
554		var->xres_virtual = var->xres;
555	if (var->yres_virtual < var->yres)
556		var->yres_virtual = var->yres;
557
558	if (var->xoffset < 0)
559		var->xoffset = 0;
560
561	if (var->yoffset < 0)
562		var->yoffset = 0;
563
564	if (var->xoffset + info->var.xres > info->var.xres_virtual)
565		var->xoffset = info->var.xres_virtual - info->var.xres;
566
567	if (var->yoffset + info->var.yres > info->var.yres_virtual)
568		var->yoffset = info->var.yres_virtual - info->var.yres;
569
570	if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
571	    (var->bits_per_pixel != 16))
572		var->bits_per_pixel = default_bpp;
573
574	switch (var->bits_per_pixel) {
575	case 16:
576		var->red.length = 5;
577		var->red.offset = 11;
578		var->red.msb_right = 0;
579
580		var->green.length = 6;
581		var->green.offset = 5;
582		var->green.msb_right = 0;
583
584		var->blue.length = 5;
585		var->blue.offset = 0;
586		var->blue.msb_right = 0;
587
588		var->transp.length = 0;
589		var->transp.offset = 0;
590		var->transp.msb_right = 0;
591		break;
592	case 24:
593		var->red.length = 8;
594		var->red.offset = 0;
595		var->red.msb_right = 0;
596
597		var->green.length = 8;
598		var->green.offset = 8;
599		var->green.msb_right = 0;
600
601		var->blue.length = 8;
602		var->blue.offset = 16;
603		var->blue.msb_right = 0;
604
605		var->transp.length = 0;
606		var->transp.offset = 0;
607		var->transp.msb_right = 0;
608		break;
609	case 32:
610		var->red.length = 8;
611		var->red.offset = 16;
612		var->red.msb_right = 0;
613
614		var->green.length = 8;
615		var->green.offset = 8;
616		var->green.msb_right = 0;
617
618		var->blue.length = 8;
619		var->blue.offset = 0;
620		var->blue.msb_right = 0;
621
622		var->transp.length = 8;
623		var->transp.offset = 24;
624		var->transp.msb_right = 0;
625
626		break;
627	}
628	/* If the pixclock is below the minimum spec'd value then set to
629	 * refresh rate for 60Hz since this is supported by most monitors.
630	 * Refer to Documentation/fb/ for calculations.
631	 */
632	if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) {
633		htotal = var->xres + var->right_margin + var->hsync_len +
634		    var->left_margin;
635		vtotal = var->yres + var->lower_margin + var->vsync_len +
636		    var->upper_margin;
637		var->pixclock = (vtotal * htotal * 6UL) / 100UL;
638		var->pixclock = KHZ2PICOS(var->pixclock);
639		pr_debug("pixclock set for 60Hz refresh = %u ps\n",
640			var->pixclock);
641	}
642
643	var->height = -1;
644	var->width = -1;
645	var->grayscale = 0;
646
647	/* Copy nonstd field to/from sync for fbset usage */
648	var->sync |= var->nonstd;
649	var->nonstd |= var->sync;
650
651	adjust_aoi_size_position(var, info);
652	return 0;
653}
654
655static void set_fix(struct fb_info *info)
656{
657	struct fb_fix_screeninfo *fix = &info->fix;
658	struct fb_var_screeninfo *var = &info->var;
659	struct mfb_info *mfbi = info->par;
660
661	strncpy(fix->id, mfbi->id, strlen(mfbi->id));
662	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
663	fix->type = FB_TYPE_PACKED_PIXELS;
664	fix->accel = FB_ACCEL_NONE;
665	fix->visual = FB_VISUAL_TRUECOLOR;
666	fix->xpanstep = 1;
667	fix->ypanstep = 1;
668}
669
670static void update_lcdc(struct fb_info *info)
671{
672	struct fb_var_screeninfo *var = &info->var;
673	struct mfb_info *mfbi = info->par;
674	struct fsl_diu_data *machine_data = mfbi->parent;
675	struct diu *hw;
676	int i, j;
677	char __iomem *cursor_base, *gamma_table_base;
678
679	u32 temp;
680
681	hw = dr.diu_reg;
682
683	if (mfbi->type == MFB_TYPE_OFF) {
684		fsl_diu_disable_panel(info);
685		return;
686	}
687
688	diu_ops.set_monitor_port(machine_data->monitor_port);
689	gamma_table_base = pool.gamma.vaddr;
690	cursor_base = pool.cursor.vaddr;
691	/* Prep for DIU init  - gamma table, cursor table */
692
693	for (i = 0; i <= 2; i++)
694	   for (j = 0; j <= 255; j++)
695	      *gamma_table_base++ = j;
696
697	diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr);
698
699	pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw);
700	disable_lcdc(info);
701
702	/* Program DIU registers */
703
704	out_be32(&hw->gamma, pool.gamma.paddr);
705	out_be32(&hw->cursor, pool.cursor.paddr);
706
707	out_be32(&hw->bgnd, 0x007F7F7F); 	/* BGND */
708	out_be32(&hw->bgnd_wb, 0); 		/* BGND_WB */
709	out_be32(&hw->disp_size, (var->yres << 16 | var->xres));
710						/* DISP SIZE */
711	pr_debug("DIU xres: %d\n", var->xres);
712	pr_debug("DIU yres: %d\n", var->yres);
713
714	out_be32(&hw->wb_size, 0); /* WB SIZE */
715	out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */
716
717	/* Horizontal and vertical configuration register */
718	temp = var->left_margin << 22 | /* BP_H */
719	       var->hsync_len << 11 |   /* PW_H */
720	       var->right_margin;       /* FP_H */
721
722	out_be32(&hw->hsyn_para, temp);
723
724	temp = var->upper_margin << 22 | /* BP_V */
725	       var->vsync_len << 11 |    /* PW_V  */
726	       var->lower_margin;        /* FP_V  */
727
728	out_be32(&hw->vsyn_para, temp);
729
730	pr_debug("DIU right_margin - %d\n", var->right_margin);
731	pr_debug("DIU left_margin - %d\n", var->left_margin);
732	pr_debug("DIU hsync_len - %d\n", var->hsync_len);
733	pr_debug("DIU upper_margin - %d\n", var->upper_margin);
734	pr_debug("DIU lower_margin - %d\n", var->lower_margin);
735	pr_debug("DIU vsync_len - %d\n", var->vsync_len);
736	pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para);
737	pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para);
738
739	diu_ops.set_pixel_clock(var->pixclock);
740
741	out_be32(&hw->syn_pol, 0);	/* SYNC SIGNALS POLARITY */
742	out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */
743	out_be32(&hw->int_status, 0);	/* INTERRUPT STATUS */
744	out_be32(&hw->plut, 0x01F5F666);
745
746	/* Enable the DIU */
747	enable_lcdc(info);
748}
749
750static int map_video_memory(struct fb_info *info)
751{
752	phys_addr_t phys;
753	u32 smem_len = info->fix.line_length * info->var.yres_virtual;
754
755	pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
756	pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
757	pr_debug("info->fix.line_length  = %d\n", info->fix.line_length);
758	pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len);
759
760	info->screen_base = fsl_diu_alloc(smem_len, &phys);
761	if (info->screen_base == NULL) {
762		printk(KERN_ERR "Unable to allocate fb memory\n");
763		return -ENOMEM;
764	}
765	mutex_lock(&info->mm_lock);
766	info->fix.smem_start = (unsigned long) phys;
767	info->fix.smem_len = smem_len;
768	mutex_unlock(&info->mm_lock);
769	info->screen_size = info->fix.smem_len;
770
771	pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
772		 info->fix.smem_start, info->fix.smem_len);
773	pr_debug("screen base %p\n", info->screen_base);
774
775	return 0;
776}
777
778static void unmap_video_memory(struct fb_info *info)
779{
780	fsl_diu_free(info->screen_base, info->fix.smem_len);
781	mutex_lock(&info->mm_lock);
782	info->screen_base = NULL;
783	info->fix.smem_start = 0;
784	info->fix.smem_len = 0;
785	mutex_unlock(&info->mm_lock);
786}
787
788/*
789 * Using the fb_var_screeninfo in fb_info we set the aoi of this
790 * particular framebuffer. It is a light version of fsl_diu_set_par.
791 */
792static int fsl_diu_set_aoi(struct fb_info *info)
793{
794	struct fb_var_screeninfo *var = &info->var;
795	struct mfb_info *mfbi = info->par;
796	struct diu_ad *ad = mfbi->ad;
797
798	/* AOI should not be greater than display size */
799	ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
800	ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
801	return 0;
802}
803
804/*
805 * Using the fb_var_screeninfo in fb_info we set the resolution of this
806 * particular framebuffer. This function alters the fb_fix_screeninfo stored
807 * in fb_info. It does not alter var in fb_info since we are using that
808 * data. This means we depend on the data in var inside fb_info to be
809 * supported by the hardware. fsl_diu_check_var is always called before
810 * fsl_diu_set_par to ensure this.
811 */
812static int fsl_diu_set_par(struct fb_info *info)
813{
814	unsigned long len;
815	struct fb_var_screeninfo *var = &info->var;
816	struct mfb_info *mfbi = info->par;
817	struct fsl_diu_data *machine_data = mfbi->parent;
818	struct diu_ad *ad = mfbi->ad;
819	struct diu *hw;
820
821	hw = dr.diu_reg;
822
823	set_fix(info);
824	mfbi->cursor_reset = 1;
825
826	len = info->var.yres_virtual * info->fix.line_length;
827	/* Alloc & dealloc each time resolution/bpp change */
828	if (len != info->fix.smem_len) {
829		if (info->fix.smem_start)
830			unmap_video_memory(info);
831		pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len);
832
833		/* Memory allocation for framebuffer */
834		if (map_video_memory(info)) {
835			printk(KERN_ERR "Unable to allocate fb memory 1\n");
836			return -ENOMEM;
837		}
838	}
839
840	ad->pix_fmt =
841		diu_ops.get_pixel_format(var->bits_per_pixel,
842					 machine_data->monitor_port);
843	ad->addr    = cpu_to_le32(info->fix.smem_start);
844	ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
845				var->xres_virtual) | mfbi->g_alpha;
846	/* AOI should not be greater than display size */
847	ad->aoi_size 	= cpu_to_le32((var->yres << 16) | var->xres);
848	ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
849	ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
850
851	/* Disable chroma keying function */
852	ad->ckmax_r = 0;
853	ad->ckmax_g = 0;
854	ad->ckmax_b = 0;
855
856	ad->ckmin_r = 255;
857	ad->ckmin_g = 255;
858	ad->ckmin_b = 255;
859
860	if (mfbi->index == 0)
861		update_lcdc(info);
862	return 0;
863}
864
865static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
866{
867	return ((val<<width) + 0x7FFF - val)>>16;
868}
869
870/*
871 * Set a single color register. The values supplied have a 16 bit magnitude
872 * which needs to be scaled in this function for the hardware. Things to take
873 * into consideration are how many color registers, if any, are supported with
874 * the current color visual. With truecolor mode no color palettes are
875 * supported. Here a psuedo palette is created which we store the value in
876 * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
877 * color palette.
878 */
879static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green,
880			   unsigned blue, unsigned transp, struct fb_info *info)
881{
882	int ret = 1;
883
884	/*
885	 * If greyscale is true, then we convert the RGB value
886	 * to greyscale no matter what visual we are using.
887	 */
888	if (info->var.grayscale)
889		red = green = blue = (19595 * red + 38470 * green +
890				      7471 * blue) >> 16;
891	switch (info->fix.visual) {
892	case FB_VISUAL_TRUECOLOR:
893		/*
894		 * 16-bit True Colour.  We encode the RGB value
895		 * according to the RGB bitfield information.
896		 */
897		if (regno < 16) {
898			u32 *pal = info->pseudo_palette;
899			u32 v;
900
901			red = CNVT_TOHW(red, info->var.red.length);
902			green = CNVT_TOHW(green, info->var.green.length);
903			blue = CNVT_TOHW(blue, info->var.blue.length);
904			transp = CNVT_TOHW(transp, info->var.transp.length);
905
906			v = (red << info->var.red.offset) |
907			    (green << info->var.green.offset) |
908			    (blue << info->var.blue.offset) |
909			    (transp << info->var.transp.offset);
910
911			pal[regno] = v;
912			ret = 0;
913		}
914		break;
915	case FB_VISUAL_STATIC_PSEUDOCOLOR:
916	case FB_VISUAL_PSEUDOCOLOR:
917		break;
918	}
919
920	return ret;
921}
922
923/*
924 * Pan (or wrap, depending on the `vmode' field) the display using the
925 * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values
926 * don't fit, return -EINVAL.
927 */
928static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
929			     struct fb_info *info)
930{
931	if ((info->var.xoffset == var->xoffset) &&
932	    (info->var.yoffset == var->yoffset))
933		return 0;	/* No change, do nothing */
934
935	if (var->xoffset < 0 || var->yoffset < 0
936	    || var->xoffset + info->var.xres > info->var.xres_virtual
937	    || var->yoffset + info->var.yres > info->var.yres_virtual)
938		return -EINVAL;
939
940	info->var.xoffset = var->xoffset;
941	info->var.yoffset = var->yoffset;
942
943	if (var->vmode & FB_VMODE_YWRAP)
944		info->var.vmode |= FB_VMODE_YWRAP;
945	else
946		info->var.vmode &= ~FB_VMODE_YWRAP;
947
948	fsl_diu_set_aoi(info);
949
950	return 0;
951}
952
953/*
954 * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking
955 * succeeded, != 0 if un-/blanking failed.
956 * blank_mode == 2: suspend vsync
957 * blank_mode == 3: suspend hsync
958 * blank_mode == 4: powerdown
959 */
960static int fsl_diu_blank(int blank_mode, struct fb_info *info)
961{
962	struct mfb_info *mfbi = info->par;
963
964	mfbi->blank = blank_mode;
965
966	switch (blank_mode) {
967	case FB_BLANK_VSYNC_SUSPEND:
968	case FB_BLANK_HSYNC_SUSPEND:
969	case FB_BLANK_NORMAL:
970	/*	fsl_diu_disable_panel(info);*/
971		break;
972	case FB_BLANK_POWERDOWN:
973	/*	disable_lcdc(info);	*/
974		break;
975	case FB_BLANK_UNBLANK:
976	/*	fsl_diu_enable_panel(info);*/
977		break;
978	}
979
980	return 0;
981}
982
983static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
984		       unsigned long arg)
985{
986	struct mfb_info *mfbi = info->par;
987	struct diu_ad *ad = mfbi->ad;
988	struct mfb_chroma_key ck;
989	unsigned char global_alpha;
990	struct aoi_display_offset aoi_d;
991	__u32 pix_fmt;
992	void __user *buf = (void __user *)arg;
993
994	if (!arg)
995		return -EINVAL;
996	switch (cmd) {
997	case MFB_SET_PIXFMT:
998		if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
999			return -EFAULT;
1000		ad->pix_fmt = pix_fmt;
1001		pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt);
1002		break;
1003	case MFB_GET_PIXFMT:
1004		pix_fmt = ad->pix_fmt;
1005		if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
1006			return -EFAULT;
1007		pr_debug("get pixel format 0x%08x\n", ad->pix_fmt);
1008		break;
1009	case MFB_SET_AOID:
1010		if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
1011			return -EFAULT;
1012		mfbi->x_aoi_d = aoi_d.x_aoi_d;
1013		mfbi->y_aoi_d = aoi_d.y_aoi_d;
1014		pr_debug("set AOI display offset of index %d to (%d,%d)\n",
1015				 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
1016		fsl_diu_check_var(&info->var, info);
1017		fsl_diu_set_aoi(info);
1018		break;
1019	case MFB_GET_AOID:
1020		aoi_d.x_aoi_d = mfbi->x_aoi_d;
1021		aoi_d.y_aoi_d = mfbi->y_aoi_d;
1022		if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
1023			return -EFAULT;
1024		pr_debug("get AOI display offset of index %d (%d,%d)\n",
1025				mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d);
1026		break;
1027	case MFB_GET_ALPHA:
1028		global_alpha = mfbi->g_alpha;
1029		if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
1030			return -EFAULT;
1031		pr_debug("get global alpha of index %d\n", mfbi->index);
1032		break;
1033	case MFB_SET_ALPHA:
1034		/* set panel information */
1035		if (copy_from_user(&global_alpha, buf, sizeof(global_alpha)))
1036			return -EFAULT;
1037		ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
1038							(global_alpha & 0xff);
1039		mfbi->g_alpha = global_alpha;
1040		pr_debug("set global alpha for index %d\n", mfbi->index);
1041		break;
1042	case MFB_SET_CHROMA_KEY:
1043		/* set panel winformation */
1044		if (copy_from_user(&ck, buf, sizeof(ck)))
1045			return -EFAULT;
1046
1047		if (ck.enable &&
1048		   (ck.red_max < ck.red_min ||
1049		    ck.green_max < ck.green_min ||
1050		    ck.blue_max < ck.blue_min))
1051			return -EINVAL;
1052
1053		if (!ck.enable) {
1054			ad->ckmax_r = 0;
1055			ad->ckmax_g = 0;
1056			ad->ckmax_b = 0;
1057			ad->ckmin_r = 255;
1058			ad->ckmin_g = 255;
1059			ad->ckmin_b = 255;
1060		} else {
1061			ad->ckmax_r = ck.red_max;
1062			ad->ckmax_g = ck.green_max;
1063			ad->ckmax_b = ck.blue_max;
1064			ad->ckmin_r = ck.red_min;
1065			ad->ckmin_g = ck.green_min;
1066			ad->ckmin_b = ck.blue_min;
1067		}
1068		pr_debug("set chroma key\n");
1069		break;
1070	case FBIOGET_GWINFO:
1071		if (mfbi->type == MFB_TYPE_OFF)
1072			return -ENODEV;
1073		/* get graphic window information */
1074		if (copy_to_user(buf, ad, sizeof(*ad)))
1075			return -EFAULT;
1076		break;
1077	case FBIOGET_HWCINFO:
1078		pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO);
1079		break;
1080	case FBIOPUT_MODEINFO:
1081		pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO);
1082		break;
1083	case FBIOGET_DISPINFO:
1084		pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO);
1085		break;
1086
1087	default:
1088		printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd);
1089		return -ENOIOCTLCMD;
1090	}
1091
1092	return 0;
1093}
1094
1095/* turn on fb if count == 1
1096 */
1097static int fsl_diu_open(struct fb_info *info, int user)
1098{
1099	struct mfb_info *mfbi = info->par;
1100	int res = 0;
1101
1102	/* free boot splash memory on first /dev/fb0 open */
1103	if (!mfbi->index && diu_ops.release_bootmem)
1104		diu_ops.release_bootmem();
1105
1106	spin_lock(&diu_lock);
1107	mfbi->count++;
1108	if (mfbi->count == 1) {
1109		pr_debug("open plane index %d\n", mfbi->index);
1110		fsl_diu_check_var(&info->var, info);
1111		res = fsl_diu_set_par(info);
1112		if (res < 0)
1113			mfbi->count--;
1114		else {
1115			res = fsl_diu_enable_panel(info);
1116			if (res < 0)
1117				mfbi->count--;
1118		}
1119	}
1120
1121	spin_unlock(&diu_lock);
1122	return res;
1123}
1124
1125/* turn off fb if count == 0
1126 */
1127static int fsl_diu_release(struct fb_info *info, int user)
1128{
1129	struct mfb_info *mfbi = info->par;
1130	int res = 0;
1131
1132	spin_lock(&diu_lock);
1133	mfbi->count--;
1134	if (mfbi->count == 0) {
1135		pr_debug("release plane index %d\n", mfbi->index);
1136		res = fsl_diu_disable_panel(info);
1137		if (res < 0)
1138			mfbi->count++;
1139	}
1140	spin_unlock(&diu_lock);
1141	return res;
1142}
1143
1144static struct fb_ops fsl_diu_ops = {
1145	.owner = THIS_MODULE,
1146	.fb_check_var = fsl_diu_check_var,
1147	.fb_set_par = fsl_diu_set_par,
1148	.fb_setcolreg = fsl_diu_setcolreg,
1149	.fb_blank = fsl_diu_blank,
1150	.fb_pan_display = fsl_diu_pan_display,
1151	.fb_fillrect = cfb_fillrect,
1152	.fb_copyarea = cfb_copyarea,
1153	.fb_imageblit = cfb_imageblit,
1154	.fb_ioctl = fsl_diu_ioctl,
1155	.fb_open = fsl_diu_open,
1156	.fb_release = fsl_diu_release,
1157};
1158
1159static int init_fbinfo(struct fb_info *info)
1160{
1161	struct mfb_info *mfbi = info->par;
1162
1163	info->device = NULL;
1164	info->var.activate = FB_ACTIVATE_NOW;
1165	info->fbops = &fsl_diu_ops;
1166	info->flags = FBINFO_FLAG_DEFAULT;
1167	info->pseudo_palette = &mfbi->pseudo_palette;
1168
1169	/* Allocate colormap */
1170	fb_alloc_cmap(&info->cmap, 16, 0);
1171	return 0;
1172}
1173
1174static int __devinit install_fb(struct fb_info *info)
1175{
1176	int rc;
1177	struct mfb_info *mfbi = info->par;
1178	const char *aoi_mode, *init_aoi_mode = "320x240";
1179	struct fb_videomode *db = fsl_diu_mode_db;
1180	unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
1181	int has_default_mode = 1;
1182
1183	if (init_fbinfo(info))
1184		return -EINVAL;
1185
1186	if (mfbi->index == 0) {	/* plane 0 */
1187		if (mfbi->edid_data) {
1188			/* Now build modedb from EDID */
1189			fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
1190			fb_videomode_to_modelist(info->monspecs.modedb,
1191						 info->monspecs.modedb_len,
1192						 &info->modelist);
1193			db = info->monspecs.modedb;
1194			dbsize = info->monspecs.modedb_len;
1195		}
1196		aoi_mode = fb_mode;
1197	} else {
1198		aoi_mode = init_aoi_mode;
1199	}
1200	pr_debug("mode used = %s\n", aoi_mode);
1201	rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
1202			  &fsl_diu_default_mode, default_bpp);
1203	switch (rc) {
1204	case 1:
1205		pr_debug("using mode specified in @mode\n");
1206		break;
1207	case 2:
1208		pr_debug("using mode specified in @mode "
1209			"with ignored refresh rate\n");
1210		break;
1211	case 3:
1212		pr_debug("using mode default mode\n");
1213		break;
1214	case 4:
1215		pr_debug("using mode from list\n");
1216		break;
1217	default:
1218		pr_debug("rc = %d\n", rc);
1219		pr_debug("failed to find mode\n");
1220		/*
1221		 * For plane 0 we continue and look into
1222		 * driver's internal modedb.
1223		 */
1224		if (mfbi->index == 0 && mfbi->edid_data)
1225			has_default_mode = 0;
1226		else
1227			return -EINVAL;
1228		break;
1229	}
1230
1231	if (!has_default_mode) {
1232		rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
1233				  ARRAY_SIZE(fsl_diu_mode_db),
1234				  &fsl_diu_default_mode,
1235				  default_bpp);
1236		if (rc > 0 && rc < 5)
1237			has_default_mode = 1;
1238	}
1239
1240	/* Still not found, use preferred mode from database if any */
1241	if (!has_default_mode && info->monspecs.modedb) {
1242		struct fb_monspecs *specs = &info->monspecs;
1243		struct fb_videomode *modedb = &specs->modedb[0];
1244
1245		/*
1246		 * Get preferred timing. If not found,
1247		 * first mode in database will be used.
1248		 */
1249		if (specs->misc & FB_MISC_1ST_DETAIL) {
1250			int i;
1251
1252			for (i = 0; i < specs->modedb_len; i++) {
1253				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
1254					modedb = &specs->modedb[i];
1255					break;
1256				}
1257			}
1258		}
1259
1260		info->var.bits_per_pixel = default_bpp;
1261		fb_videomode_to_var(&info->var, modedb);
1262	}
1263
1264	pr_debug("xres_virtual %d\n", info->var.xres_virtual);
1265	pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
1266
1267	pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
1268	pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
1269
1270	if (mfbi->type == MFB_TYPE_OFF)
1271		mfbi->blank = FB_BLANK_NORMAL;
1272	else
1273		mfbi->blank = FB_BLANK_UNBLANK;
1274
1275	if (fsl_diu_check_var(&info->var, info)) {
1276		printk(KERN_ERR "fb_check_var failed");
1277		fb_dealloc_cmap(&info->cmap);
1278		return -EINVAL;
1279	}
1280
1281	if (register_framebuffer(info) < 0) {
1282		printk(KERN_ERR "register_framebuffer failed");
1283		unmap_video_memory(info);
1284		fb_dealloc_cmap(&info->cmap);
1285		return -EINVAL;
1286	}
1287
1288	mfbi->registered = 1;
1289	printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
1290		 info->node, info->fix.id);
1291
1292	return 0;
1293}
1294
1295static void uninstall_fb(struct fb_info *info)
1296{
1297	struct mfb_info *mfbi = info->par;
1298
1299	if (!mfbi->registered)
1300		return;
1301
1302	if (mfbi->index == 0)
1303		kfree(mfbi->edid_data);
1304
1305	unregister_framebuffer(info);
1306	unmap_video_memory(info);
1307	if (&info->cmap)
1308		fb_dealloc_cmap(&info->cmap);
1309
1310	mfbi->registered = 0;
1311}
1312
1313static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
1314{
1315	struct diu *hw = dr.diu_reg;
1316	unsigned int status = in_be32(&hw->int_status);
1317
1318	if (status) {
1319		if (status & INT_UNDRUN) {
1320			out_be32(&hw->diu_mode, 0);
1321			pr_debug("Err: DIU occurs underrun!\n");
1322			udelay(1);
1323			out_be32(&hw->diu_mode, 1);
1324		}
1325#if defined(CONFIG_NOT_COHERENT_CACHE)
1326		else if (status & INT_VSYNC) {
1327			unsigned int i;
1328			for (i = 0; i < coherence_data_size;
1329				i += d_cache_line_size)
1330				__asm__ __volatile__ (
1331					"dcbz 0, %[input]"
1332				::[input]"r"(&coherence_data[i]));
1333		}
1334#endif
1335		return IRQ_HANDLED;
1336	}
1337	return IRQ_NONE;
1338}
1339
1340static int request_irq_local(int irq)
1341{
1342	unsigned long status, ints;
1343	struct diu *hw;
1344	int ret;
1345
1346	hw = dr.diu_reg;
1347
1348	/* Read to clear the status */
1349	status = in_be32(&hw->int_status);
1350
1351	ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
1352	if (ret)
1353		pr_info("Request diu IRQ failed.\n");
1354	else {
1355		ints = INT_PARERR | INT_LS_BF_VS;
1356#if !defined(CONFIG_NOT_COHERENT_CACHE)
1357		ints |=	INT_VSYNC;
1358#endif
1359		if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3)
1360			ints |= INT_VSYNC_WB;
1361
1362		/* Read to clear the status */
1363		status = in_be32(&hw->int_status);
1364		out_be32(&hw->int_mask, ints);
1365	}
1366	return ret;
1367}
1368
1369static void free_irq_local(int irq)
1370{
1371	struct diu *hw = dr.diu_reg;
1372
1373	/* Disable all LCDC interrupt */
1374	out_be32(&hw->int_mask, 0x1f);
1375
1376	free_irq(irq, NULL);
1377}
1378
1379#ifdef CONFIG_PM
1380/*
1381 * Power management hooks. Note that we won't be called from IRQ context,
1382 * unlike the blank functions above, so we may sleep.
1383 */
1384static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
1385{
1386	struct fsl_diu_data *machine_data;
1387
1388	machine_data = dev_get_drvdata(&ofdev->dev);
1389	disable_lcdc(machine_data->fsl_diu_info[0]);
1390
1391	return 0;
1392}
1393
1394static int fsl_diu_resume(struct platform_device *ofdev)
1395{
1396	struct fsl_diu_data *machine_data;
1397
1398	machine_data = dev_get_drvdata(&ofdev->dev);
1399	enable_lcdc(machine_data->fsl_diu_info[0]);
1400
1401	return 0;
1402}
1403
1404#else
1405#define fsl_diu_suspend NULL
1406#define fsl_diu_resume NULL
1407#endif				/* CONFIG_PM */
1408
1409/* Align to 64-bit(8-byte), 32-byte, etc. */
1410static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size,
1411			u32 bytes_align)
1412{
1413	u32 offset, ssize;
1414	u32 mask;
1415	dma_addr_t paddr = 0;
1416
1417	ssize = size + bytes_align;
1418	buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA |
1419							     __GFP_ZERO);
1420	if (!buf->vaddr)
1421		return -ENOMEM;
1422
1423	buf->paddr = (__u32) paddr;
1424
1425	mask = bytes_align - 1;
1426	offset = (u32)buf->paddr & mask;
1427	if (offset) {
1428		buf->offset = bytes_align - offset;
1429		buf->paddr = (u32)buf->paddr + offset;
1430	} else
1431		buf->offset = 0;
1432	return 0;
1433}
1434
1435static void free_buf(struct device *dev, struct diu_addr *buf, u32 size,
1436		     u32 bytes_align)
1437{
1438	dma_free_coherent(dev, size + bytes_align,
1439				buf->vaddr, (buf->paddr - buf->offset));
1440	return;
1441}
1442
1443static ssize_t store_monitor(struct device *device,
1444	struct device_attribute *attr, const char *buf, size_t count)
1445{
1446	int old_monitor_port;
1447	unsigned long val;
1448	struct fsl_diu_data *machine_data =
1449		container_of(attr, struct fsl_diu_data, dev_attr);
1450
1451	if (strict_strtoul(buf, 10, &val))
1452		return 0;
1453
1454	old_monitor_port = machine_data->monitor_port;
1455	machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val);
1456
1457	if (old_monitor_port != machine_data->monitor_port) {
1458		/* All AOIs need adjust pixel format
1459		 * fsl_diu_set_par only change the pixsel format here
1460		 * unlikely to fail. */
1461		fsl_diu_set_par(machine_data->fsl_diu_info[0]);
1462		fsl_diu_set_par(machine_data->fsl_diu_info[1]);
1463		fsl_diu_set_par(machine_data->fsl_diu_info[2]);
1464		fsl_diu_set_par(machine_data->fsl_diu_info[3]);
1465		fsl_diu_set_par(machine_data->fsl_diu_info[4]);
1466	}
1467	return count;
1468}
1469
1470static ssize_t show_monitor(struct device *device,
1471	struct device_attribute *attr, char *buf)
1472{
1473	struct fsl_diu_data *machine_data =
1474		container_of(attr, struct fsl_diu_data, dev_attr);
1475	return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
1476}
1477
1478static int __devinit fsl_diu_probe(struct platform_device *ofdev,
1479	const struct of_device_id *match)
1480{
1481	struct device_node *np = ofdev->dev.of_node;
1482	struct mfb_info *mfbi;
1483	phys_addr_t dummy_ad_addr;
1484	int ret, i, error = 0;
1485	struct resource res;
1486	struct fsl_diu_data *machine_data;
1487	int diu_mode;
1488
1489	machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
1490	if (!machine_data)
1491		return -ENOMEM;
1492
1493	for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
1494		machine_data->fsl_diu_info[i] =
1495			framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev);
1496		if (!machine_data->fsl_diu_info[i]) {
1497			dev_err(&ofdev->dev, "cannot allocate memory\n");
1498			ret = -ENOMEM;
1499			goto error2;
1500		}
1501		mfbi = machine_data->fsl_diu_info[i]->par;
1502		memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
1503		mfbi->parent = machine_data;
1504
1505		if (mfbi->index == 0) {
1506			const u8 *prop;
1507			int len;
1508
1509			/* Get EDID */
1510			prop = of_get_property(np, "edid", &len);
1511			if (prop && len == EDID_LENGTH)
1512				mfbi->edid_data = kmemdup(prop, EDID_LENGTH,
1513							  GFP_KERNEL);
1514		}
1515	}
1516
1517	ret = of_address_to_resource(np, 0, &res);
1518	if (ret) {
1519		dev_err(&ofdev->dev, "could not obtain DIU address\n");
1520		goto error;
1521	}
1522	if (!res.start) {
1523		dev_err(&ofdev->dev, "invalid DIU address\n");
1524		goto error;
1525	}
1526	dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start);
1527
1528	dr.diu_reg = ioremap(res.start, sizeof(struct diu));
1529	if (!dr.diu_reg) {
1530		dev_err(&ofdev->dev, "Err: can't map DIU registers!\n");
1531		ret = -EFAULT;
1532		goto error2;
1533	}
1534
1535	diu_mode = in_be32(&dr.diu_reg->diu_mode);
1536	if (diu_mode != MFB_MODE1)
1537		out_be32(&dr.diu_reg->diu_mode, 0);	/* disable DIU */
1538
1539	/* Get the IRQ of the DIU */
1540	machine_data->irq = irq_of_parse_and_map(np, 0);
1541
1542	if (!machine_data->irq) {
1543		dev_err(&ofdev->dev, "could not get DIU IRQ\n");
1544		ret = -EINVAL;
1545		goto error;
1546	}
1547	machine_data->monitor_port = monitor_port;
1548
1549	/* Area descriptor memory pool aligns to 64-bit boundary */
1550	if (allocate_buf(&ofdev->dev, &pool.ad,
1551			 sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
1552		return -ENOMEM;
1553
1554	/* Get memory for Gamma Table  - 32-byte aligned memory */
1555	if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) {
1556		ret = -ENOMEM;
1557		goto error;
1558	}
1559
1560	/* For performance, cursor bitmap buffer aligns to 32-byte boundary */
1561	if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1562			 32)) {
1563		ret = -ENOMEM;
1564		goto error;
1565	}
1566
1567	i = ARRAY_SIZE(machine_data->fsl_diu_info);
1568	machine_data->dummy_ad = (struct diu_ad *)
1569			((u32)pool.ad.vaddr + pool.ad.offset) + i;
1570	machine_data->dummy_ad->paddr = pool.ad.paddr +
1571			i * sizeof(struct diu_ad);
1572	machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
1573	if (!machine_data->dummy_aoi_virt) {
1574		ret = -ENOMEM;
1575		goto error;
1576	}
1577	machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
1578	machine_data->dummy_ad->pix_fmt = 0x88882317;
1579	machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
1580	machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) |  2);
1581	machine_data->dummy_ad->offset_xyi = 0;
1582	machine_data->dummy_ad->offset_xyd = 0;
1583	machine_data->dummy_ad->next_ad = 0;
1584
1585	/*
1586	 * Let DIU display splash screen if it was pre-initialized
1587	 * by the bootloader, set dummy area descriptor otherwise.
1588	 */
1589	if (diu_mode != MFB_MODE1)
1590		out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
1591
1592	out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
1593	out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
1594
1595	for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
1596		machine_data->fsl_diu_info[i]->fix.smem_start = 0;
1597		mfbi = machine_data->fsl_diu_info[i]->par;
1598		mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
1599					+ pool.ad.offset) + i;
1600		mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
1601		ret = install_fb(machine_data->fsl_diu_info[i]);
1602		if (ret) {
1603			dev_err(&ofdev->dev,
1604				"Failed to register framebuffer %d\n",
1605				i);
1606			goto error;
1607		}
1608	}
1609
1610	if (request_irq_local(machine_data->irq)) {
1611		dev_err(machine_data->fsl_diu_info[0]->dev,
1612			"could not request irq for diu.");
1613		goto error;
1614	}
1615
1616	sysfs_attr_init(&machine_data->dev_attr.attr);
1617	machine_data->dev_attr.attr.name = "monitor";
1618	machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
1619	machine_data->dev_attr.show = show_monitor;
1620	machine_data->dev_attr.store = store_monitor;
1621	error = device_create_file(machine_data->fsl_diu_info[0]->dev,
1622				  &machine_data->dev_attr);
1623	if (error) {
1624		dev_err(machine_data->fsl_diu_info[0]->dev,
1625			"could not create sysfs %s file\n",
1626			machine_data->dev_attr.attr.name);
1627	}
1628
1629	dev_set_drvdata(&ofdev->dev, machine_data);
1630	return 0;
1631
1632error:
1633	for (i = ARRAY_SIZE(machine_data->fsl_diu_info);
1634		i > 0; i--)
1635		uninstall_fb(machine_data->fsl_diu_info[i - 1]);
1636	if (pool.ad.vaddr)
1637		free_buf(&ofdev->dev, &pool.ad,
1638			 sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
1639	if (pool.gamma.vaddr)
1640		free_buf(&ofdev->dev, &pool.gamma, 768, 32);
1641	if (pool.cursor.vaddr)
1642		free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1643			 32);
1644	if (machine_data->dummy_aoi_virt)
1645		fsl_diu_free(machine_data->dummy_aoi_virt, 64);
1646	iounmap(dr.diu_reg);
1647
1648error2:
1649	for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
1650		if (machine_data->fsl_diu_info[i])
1651			framebuffer_release(machine_data->fsl_diu_info[i]);
1652	kfree(machine_data);
1653
1654	return ret;
1655}
1656
1657
1658static int fsl_diu_remove(struct platform_device *ofdev)
1659{
1660	struct fsl_diu_data *machine_data;
1661	int i;
1662
1663	machine_data = dev_get_drvdata(&ofdev->dev);
1664	disable_lcdc(machine_data->fsl_diu_info[0]);
1665	free_irq_local(machine_data->irq);
1666	for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--)
1667		uninstall_fb(machine_data->fsl_diu_info[i - 1]);
1668	if (pool.ad.vaddr)
1669		free_buf(&ofdev->dev, &pool.ad,
1670			 sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
1671	if (pool.gamma.vaddr)
1672		free_buf(&ofdev->dev, &pool.gamma, 768, 32);
1673	if (pool.cursor.vaddr)
1674		free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2,
1675			 32);
1676	if (machine_data->dummy_aoi_virt)
1677		fsl_diu_free(machine_data->dummy_aoi_virt, 64);
1678	iounmap(dr.diu_reg);
1679	for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
1680		if (machine_data->fsl_diu_info[i])
1681			framebuffer_release(machine_data->fsl_diu_info[i]);
1682	kfree(machine_data);
1683
1684	return 0;
1685}
1686
1687#ifndef MODULE
1688static int __init fsl_diu_setup(char *options)
1689{
1690	char *opt;
1691	unsigned long val;
1692
1693	if (!options || !*options)
1694		return 0;
1695
1696	while ((opt = strsep(&options, ",")) != NULL) {
1697		if (!*opt)
1698			continue;
1699		if (!strncmp(opt, "monitor=", 8)) {
1700			if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2))
1701				monitor_port = val;
1702		} else if (!strncmp(opt, "bpp=", 4)) {
1703			if (!strict_strtoul(opt + 4, 10, &val))
1704				default_bpp = val;
1705		} else
1706			fb_mode = opt;
1707	}
1708
1709	return 0;
1710}
1711#endif
1712
1713static struct of_device_id fsl_diu_match[] = {
1714#ifdef CONFIG_PPC_MPC512x
1715	{
1716		.compatible = "fsl,mpc5121-diu",
1717	},
1718#endif
1719	{
1720		.compatible = "fsl,diu",
1721	},
1722	{}
1723};
1724MODULE_DEVICE_TABLE(of, fsl_diu_match);
1725
1726static struct of_platform_driver fsl_diu_driver = {
1727	.driver = {
1728		.name = "fsl_diu",
1729		.owner = THIS_MODULE,
1730		.of_match_table = fsl_diu_match,
1731	},
1732	.probe  	= fsl_diu_probe,
1733	.remove 	= fsl_diu_remove,
1734	.suspend	= fsl_diu_suspend,
1735	.resume		= fsl_diu_resume,
1736};
1737
1738static int __init fsl_diu_init(void)
1739{
1740#ifdef CONFIG_NOT_COHERENT_CACHE
1741	struct device_node *np;
1742	const u32 *prop;
1743#endif
1744	int ret;
1745#ifndef MODULE
1746	char *option;
1747
1748	/*
1749	 * For kernel boot options (in 'video=xxxfb:<options>' format)
1750	 */
1751	if (fb_get_options("fslfb", &option))
1752		return -ENODEV;
1753	fsl_diu_setup(option);
1754#endif
1755	printk(KERN_INFO "Freescale DIU driver\n");
1756
1757#ifdef CONFIG_NOT_COHERENT_CACHE
1758	np = of_find_node_by_type(NULL, "cpu");
1759	if (!np) {
1760		printk(KERN_ERR "Err: can't find device node 'cpu'\n");
1761		return -ENODEV;
1762	}
1763
1764	prop = of_get_property(np, "d-cache-size", NULL);
1765	if (prop == NULL) {
1766		of_node_put(np);
1767		return -ENODEV;
1768	}
1769
1770	/* Freescale PLRU requires 13/8 times the cache size to do a proper
1771	   displacement flush
1772	 */
1773	coherence_data_size = *prop * 13;
1774	coherence_data_size /= 8;
1775
1776	prop = of_get_property(np, "d-cache-line-size", NULL);
1777	if (prop == NULL) {
1778		of_node_put(np);
1779		return -ENODEV;
1780	}
1781	d_cache_line_size = *prop;
1782
1783	of_node_put(np);
1784	coherence_data = vmalloc(coherence_data_size);
1785	if (!coherence_data)
1786		return -ENOMEM;
1787#endif
1788	ret = of_register_platform_driver(&fsl_diu_driver);
1789	if (ret) {
1790		printk(KERN_ERR
1791			"fsl-diu: failed to register platform driver\n");
1792#if defined(CONFIG_NOT_COHERENT_CACHE)
1793		vfree(coherence_data);
1794#endif
1795		iounmap(dr.diu_reg);
1796	}
1797	return ret;
1798}
1799
1800static void __exit fsl_diu_exit(void)
1801{
1802	of_unregister_platform_driver(&fsl_diu_driver);
1803#if defined(CONFIG_NOT_COHERENT_CACHE)
1804	vfree(coherence_data);
1805#endif
1806}
1807
1808module_init(fsl_diu_init);
1809module_exit(fsl_diu_exit);
1810
1811MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
1812MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
1813MODULE_LICENSE("GPL");
1814
1815module_param_named(mode, fb_mode, charp, 0);
1816MODULE_PARM_DESC(mode,
1817	"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
1818module_param_named(bpp, default_bpp, ulong, 0);
1819MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
1820module_param_named(monitor, monitor_port, int, 0);
1821MODULE_PARM_DESC(monitor,
1822	"Specify the monitor port (0, 1 or 2) if supported by the platform");
1823