1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
4 *
5 *  Freescale DIU Frame Buffer device driver
6 *
7 *  Authors: Hongjun Chen <hong-jun.chen@freescale.com>
8 *           Paul Widmer <paul.widmer@freescale.com>
9 *           Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
10 *           York Sun <yorksun@freescale.com>
11 *
12 *   Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
13 */
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/string.h>
19#include <linux/slab.h>
20#include <linux/fb.h>
21#include <linux/init.h>
22#include <linux/dma-mapping.h>
23#include <linux/platform_device.h>
24#include <linux/interrupt.h>
25#include <linux/clk.h>
26#include <linux/uaccess.h>
27#include <linux/vmalloc.h>
28#include <linux/spinlock.h>
29#include <linux/of_address.h>
30#include <linux/of_irq.h>
31
32#include <sysdev/fsl_soc.h>
33#include <linux/fsl-diu-fb.h>
34#include "edid.h"
35
36#define NUM_AOIS	5	/* 1 for plane 0, 2 for planes 1 & 2 each */
37
38/* HW cursor parameters */
39#define MAX_CURS		32
40
41/* INT_STATUS/INT_MASK field descriptions */
42#define INT_VSYNC	0x01	/* Vsync interrupt  */
43#define INT_VSYNC_WB	0x02	/* Vsync interrupt for write back operation */
44#define INT_UNDRUN	0x04	/* Under run exception interrupt */
45#define INT_PARERR	0x08	/* Display parameters error interrupt */
46#define INT_LS_BF_VS	0x10	/* Lines before vsync. interrupt */
47
48/*
49 * List of supported video modes
50 *
51 * The first entry is the default video mode.  The remain entries are in
52 * order if increasing resolution and frequency.  The 320x240-60 mode is
53 * the initial AOI for the second and third planes.
54 */
55static struct fb_videomode fsl_diu_mode_db[] = {
56	{
57		.refresh	= 60,
58		.xres		= 1024,
59		.yres		= 768,
60		.pixclock	= 15385,
61		.left_margin	= 160,
62		.right_margin	= 24,
63		.upper_margin	= 29,
64		.lower_margin	= 3,
65		.hsync_len	= 136,
66		.vsync_len	= 6,
67		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
68		.vmode		= FB_VMODE_NONINTERLACED
69	},
70	{
71		.refresh	= 60,
72		.xres		= 320,
73		.yres		= 240,
74		.pixclock	= 79440,
75		.left_margin	= 16,
76		.right_margin	= 16,
77		.upper_margin	= 16,
78		.lower_margin	= 5,
79		.hsync_len	= 48,
80		.vsync_len	= 1,
81		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
82		.vmode		= FB_VMODE_NONINTERLACED
83	},
84	{
85		.refresh        = 60,
86		.xres           = 640,
87		.yres           = 480,
88		.pixclock       = 39722,
89		.left_margin    = 48,
90		.right_margin   = 16,
91		.upper_margin   = 33,
92		.lower_margin   = 10,
93		.hsync_len      = 96,
94		.vsync_len      = 2,
95		.sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
96		.vmode          = FB_VMODE_NONINTERLACED
97	},
98	{
99		.refresh        = 72,
100		.xres           = 640,
101		.yres           = 480,
102		.pixclock       = 32052,
103		.left_margin    = 128,
104		.right_margin   = 24,
105		.upper_margin   = 28,
106		.lower_margin   = 9,
107		.hsync_len      = 40,
108		.vsync_len      = 3,
109		.sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
110		.vmode          = FB_VMODE_NONINTERLACED
111	},
112	{
113		.refresh        = 75,
114		.xres           = 640,
115		.yres           = 480,
116		.pixclock       = 31747,
117		.left_margin    = 120,
118		.right_margin   = 16,
119		.upper_margin   = 16,
120		.lower_margin   = 1,
121		.hsync_len      = 64,
122		.vsync_len      = 3,
123		.sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
124		.vmode          = FB_VMODE_NONINTERLACED
125	},
126	{
127		.refresh        = 90,
128		.xres           = 640,
129		.yres           = 480,
130		.pixclock       = 25057,
131		.left_margin    = 120,
132		.right_margin   = 32,
133		.upper_margin   = 14,
134		.lower_margin   = 25,
135		.hsync_len      = 40,
136		.vsync_len      = 14,
137		.sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
138		.vmode          = FB_VMODE_NONINTERLACED
139	},
140	{
141		.refresh        = 100,
142		.xres           = 640,
143		.yres           = 480,
144		.pixclock       = 22272,
145		.left_margin    = 48,
146		.right_margin   = 32,
147		.upper_margin   = 17,
148		.lower_margin   = 22,
149		.hsync_len      = 128,
150		.vsync_len      = 12,
151		.sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
152		.vmode          = FB_VMODE_NONINTERLACED
153	},
154	{
155		.refresh	= 60,
156		.xres		= 800,
157		.yres		= 480,
158		.pixclock	= 33805,
159		.left_margin	= 96,
160		.right_margin	= 24,
161		.upper_margin	= 10,
162		.lower_margin	= 3,
163		.hsync_len	= 72,
164		.vsync_len	= 7,
165		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
166		.vmode		= FB_VMODE_NONINTERLACED
167	},
168	{
169		.refresh        = 60,
170		.xres           = 800,
171		.yres           = 600,
172		.pixclock       = 25000,
173		.left_margin    = 88,
174		.right_margin   = 40,
175		.upper_margin   = 23,
176		.lower_margin   = 1,
177		.hsync_len      = 128,
178		.vsync_len      = 4,
179		.sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
180		.vmode          = FB_VMODE_NONINTERLACED
181	},
182	{
183		.refresh	= 60,
184		.xres		= 854,
185		.yres		= 480,
186		.pixclock	= 31518,
187		.left_margin	= 104,
188		.right_margin	= 16,
189		.upper_margin	= 13,
190		.lower_margin	= 1,
191		.hsync_len	= 88,
192		.vsync_len	= 3,
193		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
194		.vmode		= FB_VMODE_NONINTERLACED
195	},
196	{
197		.refresh	= 70,
198		.xres		= 1024,
199		.yres		= 768,
200		.pixclock	= 16886,
201		.left_margin	= 3,
202		.right_margin	= 3,
203		.upper_margin	= 2,
204		.lower_margin	= 2,
205		.hsync_len	= 40,
206		.vsync_len	= 18,
207		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
208		.vmode		= FB_VMODE_NONINTERLACED
209	},
210	{
211		.refresh	= 75,
212		.xres		= 1024,
213		.yres		= 768,
214		.pixclock	= 15009,
215		.left_margin	= 3,
216		.right_margin	= 3,
217		.upper_margin	= 2,
218		.lower_margin	= 2,
219		.hsync_len	= 80,
220		.vsync_len	= 32,
221		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
222		.vmode		= FB_VMODE_NONINTERLACED
223	},
224	{
225		.refresh	= 60,
226		.xres		= 1280,
227		.yres		= 480,
228		.pixclock	= 18939,
229		.left_margin	= 353,
230		.right_margin	= 47,
231		.upper_margin	= 39,
232		.lower_margin	= 4,
233		.hsync_len	= 8,
234		.vsync_len	= 2,
235		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
236		.vmode		= FB_VMODE_NONINTERLACED
237	},
238	{
239		.refresh	= 60,
240		.xres		= 1280,
241		.yres		= 720,
242		.pixclock	= 13426,
243		.left_margin	= 192,
244		.right_margin	= 64,
245		.upper_margin	= 22,
246		.lower_margin	= 1,
247		.hsync_len	= 136,
248		.vsync_len	= 3,
249		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
250		.vmode		= FB_VMODE_NONINTERLACED
251	},
252	{
253		.refresh	= 60,
254		.xres		= 1280,
255		.yres		= 1024,
256		.pixclock	= 9375,
257		.left_margin	= 38,
258		.right_margin	= 128,
259		.upper_margin	= 2,
260		.lower_margin	= 7,
261		.hsync_len	= 216,
262		.vsync_len	= 37,
263		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
264		.vmode		= FB_VMODE_NONINTERLACED
265	},
266	{
267		.refresh	= 70,
268		.xres		= 1280,
269		.yres		= 1024,
270		.pixclock	= 9380,
271		.left_margin	= 6,
272		.right_margin	= 6,
273		.upper_margin	= 4,
274		.lower_margin	= 4,
275		.hsync_len	= 60,
276		.vsync_len	= 94,
277		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
278		.vmode		= FB_VMODE_NONINTERLACED
279	},
280	{
281		.refresh	= 75,
282		.xres		= 1280,
283		.yres		= 1024,
284		.pixclock	= 9380,
285		.left_margin	= 6,
286		.right_margin	= 6,
287		.upper_margin	= 4,
288		.lower_margin	= 4,
289		.hsync_len	= 60,
290		.vsync_len	= 15,
291		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
292		.vmode		= FB_VMODE_NONINTERLACED
293	},
294	{
295		.refresh	= 60,
296		.xres		= 1920,
297		.yres		= 1080,
298		.pixclock	= 5787,
299		.left_margin	= 328,
300		.right_margin	= 120,
301		.upper_margin	= 34,
302		.lower_margin	= 1,
303		.hsync_len	= 208,
304		.vsync_len	= 3,
305		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
306		.vmode		= FB_VMODE_NONINTERLACED
307	},
308};
309
310static char *fb_mode;
311static unsigned long default_bpp = 32;
312static enum fsl_diu_monitor_port monitor_port;
313static char *monitor_string;
314
315#if defined(CONFIG_NOT_COHERENT_CACHE)
316static u8 *coherence_data;
317static size_t coherence_data_size;
318static unsigned int d_cache_line_size;
319#endif
320
321static DEFINE_SPINLOCK(diu_lock);
322
323enum mfb_index {
324	PLANE0 = 0,	/* Plane 0, only one AOI that fills the screen */
325	PLANE1_AOI0,	/* Plane 1, first AOI */
326	PLANE1_AOI1,	/* Plane 1, second AOI */
327	PLANE2_AOI0,	/* Plane 2, first AOI */
328	PLANE2_AOI1,	/* Plane 2, second AOI */
329};
330
331struct mfb_info {
332	enum mfb_index index;
333	char *id;
334	int registered;
335	unsigned long pseudo_palette[16];
336	struct diu_ad *ad;
337	unsigned char g_alpha;
338	unsigned int count;
339	int x_aoi_d;		/* aoi display x offset to physical screen */
340	int y_aoi_d;		/* aoi display y offset to physical screen */
341	struct fsl_diu_data *parent;
342};
343
344/**
345 * struct fsl_diu_data - per-DIU data structure
346 * @dma_addr: DMA address of this structure
347 * @fsl_diu_info: fb_info objects, one per AOI
348 * @dev_attr: sysfs structure
349 * @irq: IRQ
350 * @monitor_port: the monitor port this DIU is connected to
351 * @diu_reg: pointer to the DIU hardware registers
352 * @reg_lock: spinlock for register access
353 * @dummy_aoi: video buffer for the 4x4 32-bit dummy AOI
354 * dummy_ad: DIU Area Descriptor for the dummy AOI
355 * @ad[]: Area Descriptors for each real AOI
356 * @gamma: gamma color table
357 * @cursor: hardware cursor data
358 * @blank_cursor: blank cursor for hiding cursor
359 * @next_cursor: scratch space to build load cursor
360 * @edid_data: EDID information buffer
361 * @has_edid: whether or not the EDID buffer is valid
362 *
363 * This data structure must be allocated with 32-byte alignment, so that the
364 * internal fields can be aligned properly.
365 */
366struct fsl_diu_data {
367	dma_addr_t dma_addr;
368	struct fb_info fsl_diu_info[NUM_AOIS];
369	struct mfb_info mfb[NUM_AOIS];
370	struct device_attribute dev_attr;
371	unsigned int irq;
372	enum fsl_diu_monitor_port monitor_port;
373	struct diu __iomem *diu_reg;
374	spinlock_t reg_lock;
375	u8 dummy_aoi[4 * 4 * 4];
376	struct diu_ad dummy_ad __aligned(8);
377	struct diu_ad ad[NUM_AOIS] __aligned(8);
378	u8 gamma[256 * 3] __aligned(32);
379	/* It's easier to parse the cursor data as little-endian */
380	__le16 cursor[MAX_CURS * MAX_CURS] __aligned(32);
381	/* Blank cursor data -- used to hide the cursor */
382	__le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32);
383	/* Scratch cursor data -- used to build new cursor */
384	__le16 next_cursor[MAX_CURS * MAX_CURS] __aligned(32);
385	uint8_t edid_data[EDID_LENGTH];
386	bool has_edid;
387} __aligned(32);
388
389/* Determine the DMA address of a member of the fsl_diu_data structure */
390#define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f))
391
392static const struct mfb_info mfb_template[] = {
393	{
394		.index = PLANE0,
395		.id = "Panel0",
396		.registered = 0,
397		.count = 0,
398		.x_aoi_d = 0,
399		.y_aoi_d = 0,
400	},
401	{
402		.index = PLANE1_AOI0,
403		.id = "Panel1 AOI0",
404		.registered = 0,
405		.g_alpha = 0xff,
406		.count = 0,
407		.x_aoi_d = 0,
408		.y_aoi_d = 0,
409	},
410	{
411		.index = PLANE1_AOI1,
412		.id = "Panel1 AOI1",
413		.registered = 0,
414		.g_alpha = 0xff,
415		.count = 0,
416		.x_aoi_d = 0,
417		.y_aoi_d = 480,
418	},
419	{
420		.index = PLANE2_AOI0,
421		.id = "Panel2 AOI0",
422		.registered = 0,
423		.g_alpha = 0xff,
424		.count = 0,
425		.x_aoi_d = 640,
426		.y_aoi_d = 0,
427	},
428	{
429		.index = PLANE2_AOI1,
430		.id = "Panel2 AOI1",
431		.registered = 0,
432		.g_alpha = 0xff,
433		.count = 0,
434		.x_aoi_d = 640,
435		.y_aoi_d = 480,
436	},
437};
438
439#ifdef DEBUG
440static void __attribute__ ((unused)) fsl_diu_dump(struct diu __iomem *hw)
441{
442	mb();
443	pr_debug("DIU: desc=%08x,%08x,%08x, gamma=%08x palette=%08x "
444		 "cursor=%08x curs_pos=%08x diu_mode=%08x bgnd=%08x "
445		 "disp_size=%08x hsyn_para=%08x vsyn_para=%08x syn_pol=%08x "
446		 "thresholds=%08x int_mask=%08x plut=%08x\n",
447		 hw->desc[0], hw->desc[1], hw->desc[2], hw->gamma,
448		 hw->palette, hw->cursor, hw->curs_pos, hw->diu_mode,
449		 hw->bgnd, hw->disp_size, hw->hsyn_para, hw->vsyn_para,
450		 hw->syn_pol, hw->thresholds, hw->int_mask, hw->plut);
451	rmb();
452}
453#endif
454
455/**
456 * fsl_diu_name_to_port - convert a port name to a monitor port enum
457 *
458 * Takes the name of a monitor port ("dvi", "lvds", or "dlvds") and returns
459 * the enum fsl_diu_monitor_port that corresponds to that string.
460 *
461 * For compatibility with older versions, a number ("0", "1", or "2") is also
462 * supported.
463 *
464 * If the string is unknown, DVI is assumed.
465 *
466 * If the particular port is not supported by the platform, another port
467 * (platform-specific) is chosen instead.
468 */
469static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
470{
471	enum fsl_diu_monitor_port port = FSL_DIU_PORT_DVI;
472	unsigned long val;
473
474	if (s) {
475		if (!kstrtoul(s, 10, &val) && (val <= 2))
476			port = (enum fsl_diu_monitor_port) val;
477		else if (strncmp(s, "lvds", 4) == 0)
478			port = FSL_DIU_PORT_LVDS;
479		else if (strncmp(s, "dlvds", 5) == 0)
480			port = FSL_DIU_PORT_DLVDS;
481	}
482
483	if (diu_ops.valid_monitor_port)
484		port = diu_ops.valid_monitor_port(port);
485
486	return port;
487}
488
489/*
490 * Workaround for failed writing desc register of planes.
491 * Needed with MPC5121 DIU rev 2.0 silicon.
492 */
493static void wr_reg_wa(u32 *reg, u32 val)
494{
495	do {
496		out_be32(reg, val);
497	} while (in_be32(reg) != val);
498}
499
500static void fsl_diu_enable_panel(struct fb_info *info)
501{
502	struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
503	struct diu_ad *ad = mfbi->ad;
504	struct fsl_diu_data *data = mfbi->parent;
505	struct diu __iomem *hw = data->diu_reg;
506
507	switch (mfbi->index) {
508	case PLANE0:
509		wr_reg_wa(&hw->desc[0], ad->paddr);
510		break;
511	case PLANE1_AOI0:
512		cmfbi = &data->mfb[2];
513		if (hw->desc[1] != ad->paddr) {	/* AOI0 closed */
514			if (cmfbi->count > 0)	/* AOI1 open */
515				ad->next_ad =
516					cpu_to_le32(cmfbi->ad->paddr);
517			else
518				ad->next_ad = 0;
519			wr_reg_wa(&hw->desc[1], ad->paddr);
520		}
521		break;
522	case PLANE2_AOI0:
523		cmfbi = &data->mfb[4];
524		if (hw->desc[2] != ad->paddr) {	/* AOI0 closed */
525			if (cmfbi->count > 0)	/* AOI1 open */
526				ad->next_ad =
527					cpu_to_le32(cmfbi->ad->paddr);
528			else
529				ad->next_ad = 0;
530			wr_reg_wa(&hw->desc[2], ad->paddr);
531		}
532		break;
533	case PLANE1_AOI1:
534		pmfbi = &data->mfb[1];
535		ad->next_ad = 0;
536		if (hw->desc[1] == data->dummy_ad.paddr)
537			wr_reg_wa(&hw->desc[1], ad->paddr);
538		else					/* AOI0 open */
539			pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
540		break;
541	case PLANE2_AOI1:
542		pmfbi = &data->mfb[3];
543		ad->next_ad = 0;
544		if (hw->desc[2] == data->dummy_ad.paddr)
545			wr_reg_wa(&hw->desc[2], ad->paddr);
546		else				/* AOI0 was open */
547			pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
548		break;
549	}
550}
551
552static void fsl_diu_disable_panel(struct fb_info *info)
553{
554	struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
555	struct diu_ad *ad = mfbi->ad;
556	struct fsl_diu_data *data = mfbi->parent;
557	struct diu __iomem *hw = data->diu_reg;
558
559	switch (mfbi->index) {
560	case PLANE0:
561		wr_reg_wa(&hw->desc[0], 0);
562		break;
563	case PLANE1_AOI0:
564		cmfbi = &data->mfb[2];
565		if (cmfbi->count > 0)	/* AOI1 is open */
566			wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
567					/* move AOI1 to the first */
568		else			/* AOI1 was closed */
569			wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
570					/* close AOI 0 */
571		break;
572	case PLANE2_AOI0:
573		cmfbi = &data->mfb[4];
574		if (cmfbi->count > 0)	/* AOI1 is open */
575			wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
576					/* move AOI1 to the first */
577		else			/* AOI1 was closed */
578			wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
579					/* close AOI 0 */
580		break;
581	case PLANE1_AOI1:
582		pmfbi = &data->mfb[1];
583		if (hw->desc[1] != ad->paddr) {
584				/* AOI1 is not the first in the chain */
585			if (pmfbi->count > 0)
586					/* AOI0 is open, must be the first */
587				pmfbi->ad->next_ad = 0;
588		} else			/* AOI1 is the first in the chain */
589			wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
590					/* close AOI 1 */
591		break;
592	case PLANE2_AOI1:
593		pmfbi = &data->mfb[3];
594		if (hw->desc[2] != ad->paddr) {
595				/* AOI1 is not the first in the chain */
596			if (pmfbi->count > 0)
597				/* AOI0 is open, must be the first */
598				pmfbi->ad->next_ad = 0;
599		} else		/* AOI1 is the first in the chain */
600			wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
601				/* close AOI 1 */
602		break;
603	}
604}
605
606static void enable_lcdc(struct fb_info *info)
607{
608	struct mfb_info *mfbi = info->par;
609	struct fsl_diu_data *data = mfbi->parent;
610	struct diu __iomem *hw = data->diu_reg;
611
612	out_be32(&hw->diu_mode, MFB_MODE1);
613}
614
615static void disable_lcdc(struct fb_info *info)
616{
617	struct mfb_info *mfbi = info->par;
618	struct fsl_diu_data *data = mfbi->parent;
619	struct diu __iomem *hw = data->diu_reg;
620
621	out_be32(&hw->diu_mode, 0);
622}
623
624static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
625				struct fb_info *info)
626{
627	struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
628	struct fsl_diu_data *data = mfbi->parent;
629	int available_height, upper_aoi_bottom;
630	enum mfb_index index = mfbi->index;
631	int lower_aoi_is_open, upper_aoi_is_open;
632	__u32 base_plane_width, base_plane_height, upper_aoi_height;
633
634	base_plane_width = data->fsl_diu_info[0].var.xres;
635	base_plane_height = data->fsl_diu_info[0].var.yres;
636
637	if (mfbi->x_aoi_d < 0)
638		mfbi->x_aoi_d = 0;
639	if (mfbi->y_aoi_d < 0)
640		mfbi->y_aoi_d = 0;
641	switch (index) {
642	case PLANE0:
643		if (mfbi->x_aoi_d != 0)
644			mfbi->x_aoi_d = 0;
645		if (mfbi->y_aoi_d != 0)
646			mfbi->y_aoi_d = 0;
647		break;
648	case PLANE1_AOI0:
649	case PLANE2_AOI0:
650		lower_aoi_mfbi = data->fsl_diu_info[index+1].par;
651		lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
652		if (var->xres > base_plane_width)
653			var->xres = base_plane_width;
654		if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
655			mfbi->x_aoi_d = base_plane_width - var->xres;
656
657		if (lower_aoi_is_open)
658			available_height = lower_aoi_mfbi->y_aoi_d;
659		else
660			available_height = base_plane_height;
661		if (var->yres > available_height)
662			var->yres = available_height;
663		if ((mfbi->y_aoi_d + var->yres) > available_height)
664			mfbi->y_aoi_d = available_height - var->yres;
665		break;
666	case PLANE1_AOI1:
667	case PLANE2_AOI1:
668		upper_aoi_mfbi = data->fsl_diu_info[index-1].par;
669		upper_aoi_height = data->fsl_diu_info[index-1].var.yres;
670		upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
671		upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
672		if (var->xres > base_plane_width)
673			var->xres = base_plane_width;
674		if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
675			mfbi->x_aoi_d = base_plane_width - var->xres;
676		if (mfbi->y_aoi_d < 0)
677			mfbi->y_aoi_d = 0;
678		if (upper_aoi_is_open) {
679			if (mfbi->y_aoi_d < upper_aoi_bottom)
680				mfbi->y_aoi_d = upper_aoi_bottom;
681			available_height = base_plane_height
682						- upper_aoi_bottom;
683		} else
684			available_height = base_plane_height;
685		if (var->yres > available_height)
686			var->yres = available_height;
687		if ((mfbi->y_aoi_d + var->yres) > base_plane_height)
688			mfbi->y_aoi_d = base_plane_height - var->yres;
689		break;
690	}
691}
692/*
693 * Checks to see if the hardware supports the state requested by var passed
694 * in. This function does not alter the hardware state! If the var passed in
695 * is slightly off by what the hardware can support then we alter the var
696 * PASSED in to what we can do. If the hardware doesn't support mode change
697 * a -EINVAL will be returned by the upper layers.
698 */
699static int fsl_diu_check_var(struct fb_var_screeninfo *var,
700				struct fb_info *info)
701{
702	if (var->xres_virtual < var->xres)
703		var->xres_virtual = var->xres;
704	if (var->yres_virtual < var->yres)
705		var->yres_virtual = var->yres;
706
707	if (var->xoffset + info->var.xres > info->var.xres_virtual)
708		var->xoffset = info->var.xres_virtual - info->var.xres;
709
710	if (var->yoffset + info->var.yres > info->var.yres_virtual)
711		var->yoffset = info->var.yres_virtual - info->var.yres;
712
713	if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
714	    (var->bits_per_pixel != 16))
715		var->bits_per_pixel = default_bpp;
716
717	switch (var->bits_per_pixel) {
718	case 16:
719		var->red.length = 5;
720		var->red.offset = 11;
721		var->red.msb_right = 0;
722
723		var->green.length = 6;
724		var->green.offset = 5;
725		var->green.msb_right = 0;
726
727		var->blue.length = 5;
728		var->blue.offset = 0;
729		var->blue.msb_right = 0;
730
731		var->transp.length = 0;
732		var->transp.offset = 0;
733		var->transp.msb_right = 0;
734		break;
735	case 24:
736		var->red.length = 8;
737		var->red.offset = 0;
738		var->red.msb_right = 0;
739
740		var->green.length = 8;
741		var->green.offset = 8;
742		var->green.msb_right = 0;
743
744		var->blue.length = 8;
745		var->blue.offset = 16;
746		var->blue.msb_right = 0;
747
748		var->transp.length = 0;
749		var->transp.offset = 0;
750		var->transp.msb_right = 0;
751		break;
752	case 32:
753		var->red.length = 8;
754		var->red.offset = 16;
755		var->red.msb_right = 0;
756
757		var->green.length = 8;
758		var->green.offset = 8;
759		var->green.msb_right = 0;
760
761		var->blue.length = 8;
762		var->blue.offset = 0;
763		var->blue.msb_right = 0;
764
765		var->transp.length = 8;
766		var->transp.offset = 24;
767		var->transp.msb_right = 0;
768
769		break;
770	}
771
772	var->height = -1;
773	var->width = -1;
774	var->grayscale = 0;
775
776	/* Copy nonstd field to/from sync for fbset usage */
777	var->sync |= var->nonstd;
778	var->nonstd |= var->sync;
779
780	adjust_aoi_size_position(var, info);
781	return 0;
782}
783
784static void set_fix(struct fb_info *info)
785{
786	struct fb_fix_screeninfo *fix = &info->fix;
787	struct fb_var_screeninfo *var = &info->var;
788	struct mfb_info *mfbi = info->par;
789
790	strncpy(fix->id, mfbi->id, sizeof(fix->id));
791	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
792	fix->type = FB_TYPE_PACKED_PIXELS;
793	fix->accel = FB_ACCEL_NONE;
794	fix->visual = FB_VISUAL_TRUECOLOR;
795	fix->xpanstep = 1;
796	fix->ypanstep = 1;
797}
798
799static void update_lcdc(struct fb_info *info)
800{
801	struct fb_var_screeninfo *var = &info->var;
802	struct mfb_info *mfbi = info->par;
803	struct fsl_diu_data *data = mfbi->parent;
804	struct diu __iomem *hw;
805	int i, j;
806	u8 *gamma_table_base;
807
808	u32 temp;
809
810	hw = data->diu_reg;
811
812	if (diu_ops.set_monitor_port)
813		diu_ops.set_monitor_port(data->monitor_port);
814	gamma_table_base = data->gamma;
815
816	/* Prep for DIU init  - gamma table, cursor table */
817
818	for (i = 0; i <= 2; i++)
819		for (j = 0; j <= 255; j++)
820			*gamma_table_base++ = j;
821
822	if (diu_ops.set_gamma_table)
823		diu_ops.set_gamma_table(data->monitor_port, data->gamma);
824
825	disable_lcdc(info);
826
827	/* Program DIU registers */
828
829	out_be32(&hw->gamma, DMA_ADDR(data, gamma));
830
831	out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */
832	out_be32(&hw->disp_size, (var->yres << 16) | var->xres);
833
834	/* Horizontal and vertical configuration register */
835	temp = var->left_margin << 22 | /* BP_H */
836	       var->hsync_len << 11 |   /* PW_H */
837	       var->right_margin;       /* FP_H */
838
839	out_be32(&hw->hsyn_para, temp);
840
841	temp = var->upper_margin << 22 | /* BP_V */
842	       var->vsync_len << 11 |    /* PW_V  */
843	       var->lower_margin;        /* FP_V  */
844
845	out_be32(&hw->vsyn_para, temp);
846
847	diu_ops.set_pixel_clock(var->pixclock);
848
849#ifndef CONFIG_PPC_MPC512x
850	/*
851	 * The PLUT register is defined differently on the MPC5121 than it
852	 * is on other SOCs.  Unfortunately, there's no documentation that
853	 * explains how it's supposed to be programmed, so for now, we leave
854	 * it at the default value on the MPC5121.
855	 *
856	 * For other SOCs, program it for the highest priority, which will
857	 * reduce the chance of underrun. Technically, we should scale the
858	 * priority to match the screen resolution, but doing that properly
859	 * requires delicate fine-tuning for each use-case.
860	 */
861	out_be32(&hw->plut, 0x01F5F666);
862#endif
863
864	/* Enable the DIU */
865	enable_lcdc(info);
866}
867
868static int map_video_memory(struct fb_info *info)
869{
870	u32 smem_len = info->fix.line_length * info->var.yres_virtual;
871	void *p;
872
873	p = alloc_pages_exact(smem_len, GFP_DMA | __GFP_ZERO);
874	if (!p) {
875		dev_err(info->dev, "unable to allocate fb memory\n");
876		return -ENOMEM;
877	}
878	mutex_lock(&info->mm_lock);
879	info->screen_base = p;
880	info->fix.smem_start = virt_to_phys(info->screen_base);
881	info->fix.smem_len = smem_len;
882	mutex_unlock(&info->mm_lock);
883	info->screen_size = info->fix.smem_len;
884
885	return 0;
886}
887
888static void unmap_video_memory(struct fb_info *info)
889{
890	void *p = info->screen_base;
891	size_t l = info->fix.smem_len;
892
893	mutex_lock(&info->mm_lock);
894	info->screen_base = NULL;
895	info->fix.smem_start = 0;
896	info->fix.smem_len = 0;
897	mutex_unlock(&info->mm_lock);
898
899	if (p)
900		free_pages_exact(p, l);
901}
902
903/*
904 * Using the fb_var_screeninfo in fb_info we set the aoi of this
905 * particular framebuffer. It is a light version of fsl_diu_set_par.
906 */
907static int fsl_diu_set_aoi(struct fb_info *info)
908{
909	struct fb_var_screeninfo *var = &info->var;
910	struct mfb_info *mfbi = info->par;
911	struct diu_ad *ad = mfbi->ad;
912
913	/* AOI should not be greater than display size */
914	ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
915	ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
916	return 0;
917}
918
919/**
920 * fsl_diu_get_pixel_format: return the pixel format for a given color depth
921 *
922 * The pixel format is a 32-bit value that determine which bits in each
923 * pixel are to be used for each color.  This is the default function used
924 * if the platform does not define its own version.
925 */
926static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel)
927{
928#define PF_BYTE_F		0x10000000
929#define PF_ALPHA_C_MASK		0x0E000000
930#define PF_ALPHA_C_SHIFT	25
931#define PF_BLUE_C_MASK		0x01800000
932#define PF_BLUE_C_SHIFT		23
933#define PF_GREEN_C_MASK		0x00600000
934#define PF_GREEN_C_SHIFT	21
935#define PF_RED_C_MASK		0x00180000
936#define PF_RED_C_SHIFT		19
937#define PF_PALETTE		0x00040000
938#define PF_PIXEL_S_MASK		0x00030000
939#define PF_PIXEL_S_SHIFT	16
940#define PF_COMP_3_MASK		0x0000F000
941#define PF_COMP_3_SHIFT		12
942#define PF_COMP_2_MASK		0x00000F00
943#define PF_COMP_2_SHIFT		8
944#define PF_COMP_1_MASK		0x000000F0
945#define PF_COMP_1_SHIFT		4
946#define PF_COMP_0_MASK		0x0000000F
947#define PF_COMP_0_SHIFT		0
948
949#define MAKE_PF(alpha, red, green, blue, size, c0, c1, c2, c3) \
950	cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \
951	(blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \
952	(red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \
953	(c2 << PF_COMP_2_SHIFT) | (c1 << PF_COMP_1_SHIFT) | \
954	(c0 << PF_COMP_0_SHIFT) | (size << PF_PIXEL_S_SHIFT))
955
956	switch (bits_per_pixel) {
957	case 32:
958		/* 0x88883316 */
959		return MAKE_PF(3, 2, 1, 0, 3, 8, 8, 8, 8);
960	case 24:
961		/* 0x88082219 */
962		return MAKE_PF(4, 0, 1, 2, 2, 8, 8, 8, 0);
963	case 16:
964		/* 0x65053118 */
965		return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0);
966	default:
967		pr_err("fsl-diu: unsupported color depth %u\n", bits_per_pixel);
968		return 0;
969	}
970}
971
972/*
973 * Copies a cursor image from user space to the proper place in driver
974 * memory so that the hardware can display the cursor image.
975 *
976 * Cursor data is represented as a sequence of 'width' bits packed into bytes.
977 * That is, the first 8 bits are in the first byte, the second 8 bits in the
978 * second byte, and so on.  Therefore, the each row of the cursor is (width +
979 * 7) / 8 bytes of 'data'
980 *
981 * The DIU only supports cursors up to 32x32 (MAX_CURS).  We reject cursors
982 * larger than this, so we already know that 'width' <= 32.  Therefore, we can
983 * simplify our code by using a 32-bit big-endian integer ("line") to read in
984 * a single line of pixels, and only look at the top 'width' bits of that
985 * integer.
986 *
987 * This could result in an unaligned 32-bit read.  For example, if the cursor
988 * is 24x24, then the first three bytes of 'image' contain the pixel data for
989 * the top line of the cursor.  We do a 32-bit read of 'image', but we look
990 * only at the top 24 bits.  Then we increment 'image' by 3 bytes.  The next
991 * read is unaligned.  The only problem is that we might read past the end of
992 * 'image' by 1-3 bytes, but that should not cause any problems.
993 */
994static void fsl_diu_load_cursor_image(struct fb_info *info,
995	const void *image, uint16_t bg, uint16_t fg,
996	unsigned int width, unsigned int height)
997{
998	struct mfb_info *mfbi = info->par;
999	struct fsl_diu_data *data = mfbi->parent;
1000	__le16 *cursor = data->cursor;
1001	__le16 _fg = cpu_to_le16(fg);
1002	__le16 _bg = cpu_to_le16(bg);
1003	unsigned int h, w;
1004
1005	for (h = 0; h < height; h++) {
1006		uint32_t mask = 1 << 31;
1007		uint32_t line = be32_to_cpup(image);
1008
1009		for (w = 0; w < width; w++) {
1010			cursor[w] = (line & mask) ? _fg : _bg;
1011			mask >>= 1;
1012		}
1013
1014		cursor += MAX_CURS;
1015		image += DIV_ROUND_UP(width, 8);
1016	}
1017}
1018
1019/*
1020 * Set a hardware cursor.  The image data for the cursor is passed via the
1021 * fb_cursor object.
1022 */
1023static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
1024{
1025	struct mfb_info *mfbi = info->par;
1026	struct fsl_diu_data *data = mfbi->parent;
1027	struct diu __iomem *hw = data->diu_reg;
1028
1029	if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
1030		return -EINVAL;
1031
1032	/* The cursor size has changed */
1033	if (cursor->set & FB_CUR_SETSIZE) {
1034		/*
1035		 * The DIU cursor is a fixed size, so when we get this
1036		 * message, instead of resizing the cursor, we just clear
1037		 * all the image data, in expectation of new data.  However,
1038		 * in tests this control does not appear to be normally
1039		 * called.
1040		 */
1041		memset(data->cursor, 0, sizeof(data->cursor));
1042	}
1043
1044	/* The cursor position has changed (cursor->image.dx|dy) */
1045	if (cursor->set & FB_CUR_SETPOS) {
1046		uint32_t xx, yy;
1047
1048		yy = (cursor->image.dy - info->var.yoffset) & 0x7ff;
1049		xx = (cursor->image.dx - info->var.xoffset) & 0x7ff;
1050
1051		out_be32(&hw->curs_pos, yy << 16 | xx);
1052	}
1053
1054	/*
1055	 * FB_CUR_SETIMAGE - the cursor image has changed
1056	 * FB_CUR_SETCMAP  - the cursor colors has changed
1057	 * FB_CUR_SETSHAPE - the cursor bitmask has changed
1058	 */
1059	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
1060		/*
1061		 * Determine the size of the cursor image data.  Normally,
1062		 * it's 8x16.
1063		 */
1064		unsigned int image_size =
1065			DIV_ROUND_UP(cursor->image.width, 8) *
1066			cursor->image.height;
1067		unsigned int image_words =
1068			DIV_ROUND_UP(image_size, sizeof(uint32_t));
1069		unsigned int bg_idx = cursor->image.bg_color;
1070		unsigned int fg_idx = cursor->image.fg_color;
1071		uint32_t *image, *source, *mask;
1072		uint16_t fg, bg;
1073		unsigned int i;
1074
1075		if (info->state != FBINFO_STATE_RUNNING)
1076			return 0;
1077
1078		bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
1079		     ((info->cmap.green[bg_idx] & 0xf8) << 2) |
1080		     ((info->cmap.blue[bg_idx] & 0xf8) >> 3) |
1081		     1 << 15;
1082
1083		fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
1084		     ((info->cmap.green[fg_idx] & 0xf8) << 2) |
1085		     ((info->cmap.blue[fg_idx] & 0xf8) >> 3) |
1086		     1 << 15;
1087
1088		/* Use 32-bit operations on the data to improve performance */
1089		image = (uint32_t *)data->next_cursor;
1090		source = (uint32_t *)cursor->image.data;
1091		mask = (uint32_t *)cursor->mask;
1092
1093		if (cursor->rop == ROP_XOR)
1094			for (i = 0; i < image_words; i++)
1095				image[i] = source[i] ^ mask[i];
1096		else
1097			for (i = 0; i < image_words; i++)
1098				image[i] = source[i] & mask[i];
1099
1100		fsl_diu_load_cursor_image(info, image, bg, fg,
1101			cursor->image.width, cursor->image.height);
1102	}
1103
1104	/*
1105	 * Show or hide the cursor.  The cursor data is always stored in the
1106	 * 'cursor' memory block, and the actual cursor position is always in
1107	 * the DIU's CURS_POS register.  To hide the cursor, we redirect the
1108	 * CURSOR register to a blank cursor.  The show the cursor, we
1109	 * redirect the CURSOR register to the real cursor data.
1110	 */
1111	if (cursor->enable)
1112		out_be32(&hw->cursor, DMA_ADDR(data, cursor));
1113	else
1114		out_be32(&hw->cursor, DMA_ADDR(data, blank_cursor));
1115
1116	return 0;
1117}
1118
1119/*
1120 * Using the fb_var_screeninfo in fb_info we set the resolution of this
1121 * particular framebuffer. This function alters the fb_fix_screeninfo stored
1122 * in fb_info. It does not alter var in fb_info since we are using that
1123 * data. This means we depend on the data in var inside fb_info to be
1124 * supported by the hardware. fsl_diu_check_var is always called before
1125 * fsl_diu_set_par to ensure this.
1126 */
1127static int fsl_diu_set_par(struct fb_info *info)
1128{
1129	unsigned long len;
1130	struct fb_var_screeninfo *var = &info->var;
1131	struct mfb_info *mfbi = info->par;
1132	struct fsl_diu_data *data = mfbi->parent;
1133	struct diu_ad *ad = mfbi->ad;
1134	struct diu __iomem *hw;
1135
1136	hw = data->diu_reg;
1137
1138	set_fix(info);
1139
1140	len = info->var.yres_virtual * info->fix.line_length;
1141	/* Alloc & dealloc each time resolution/bpp change */
1142	if (len != info->fix.smem_len) {
1143		if (info->fix.smem_start)
1144			unmap_video_memory(info);
1145
1146		/* Memory allocation for framebuffer */
1147		if (map_video_memory(info)) {
1148			dev_err(info->dev, "unable to allocate fb memory 1\n");
1149			return -ENOMEM;
1150		}
1151	}
1152
1153	if (diu_ops.get_pixel_format)
1154		ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port,
1155						       var->bits_per_pixel);
1156	else
1157		ad->pix_fmt = fsl_diu_get_pixel_format(var->bits_per_pixel);
1158
1159	ad->addr    = cpu_to_le32(info->fix.smem_start);
1160	ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
1161				var->xres_virtual) | mfbi->g_alpha;
1162	/* AOI should not be greater than display size */
1163	ad->aoi_size 	= cpu_to_le32((var->yres << 16) | var->xres);
1164	ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
1165	ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
1166
1167	/* Disable chroma keying function */
1168	ad->ckmax_r = 0;
1169	ad->ckmax_g = 0;
1170	ad->ckmax_b = 0;
1171
1172	ad->ckmin_r = 255;
1173	ad->ckmin_g = 255;
1174	ad->ckmin_b = 255;
1175
1176	if (mfbi->index == PLANE0)
1177		update_lcdc(info);
1178	return 0;
1179}
1180
1181static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
1182{
1183	return ((val << width) + 0x7FFF - val) >> 16;
1184}
1185
1186/*
1187 * Set a single color register. The values supplied have a 16 bit magnitude
1188 * which needs to be scaled in this function for the hardware. Things to take
1189 * into consideration are how many color registers, if any, are supported with
1190 * the current color visual. With truecolor mode no color palettes are
1191 * supported. Here a pseudo palette is created which we store the value in
1192 * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
1193 * color palette.
1194 */
1195static int fsl_diu_setcolreg(unsigned int regno, unsigned int red,
1196			     unsigned int green, unsigned int blue,
1197			     unsigned int transp, struct fb_info *info)
1198{
1199	int ret = 1;
1200
1201	/*
1202	 * If greyscale is true, then we convert the RGB value
1203	 * to greyscale no matter what visual we are using.
1204	 */
1205	if (info->var.grayscale)
1206		red = green = blue = (19595 * red + 38470 * green +
1207				      7471 * blue) >> 16;
1208	switch (info->fix.visual) {
1209	case FB_VISUAL_TRUECOLOR:
1210		/*
1211		 * 16-bit True Colour.  We encode the RGB value
1212		 * according to the RGB bitfield information.
1213		 */
1214		if (regno < 16) {
1215			u32 *pal = info->pseudo_palette;
1216			u32 v;
1217
1218			red = CNVT_TOHW(red, info->var.red.length);
1219			green = CNVT_TOHW(green, info->var.green.length);
1220			blue = CNVT_TOHW(blue, info->var.blue.length);
1221			transp = CNVT_TOHW(transp, info->var.transp.length);
1222
1223			v = (red << info->var.red.offset) |
1224			    (green << info->var.green.offset) |
1225			    (blue << info->var.blue.offset) |
1226			    (transp << info->var.transp.offset);
1227
1228			pal[regno] = v;
1229			ret = 0;
1230		}
1231		break;
1232	}
1233
1234	return ret;
1235}
1236
1237/*
1238 * Pan (or wrap, depending on the `vmode' field) the display using the
1239 * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values
1240 * don't fit, return -EINVAL.
1241 */
1242static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
1243			     struct fb_info *info)
1244{
1245	if ((info->var.xoffset == var->xoffset) &&
1246	    (info->var.yoffset == var->yoffset))
1247		return 0;	/* No change, do nothing */
1248
1249	if (var->xoffset + info->var.xres > info->var.xres_virtual
1250	    || var->yoffset + info->var.yres > info->var.yres_virtual)
1251		return -EINVAL;
1252
1253	info->var.xoffset = var->xoffset;
1254	info->var.yoffset = var->yoffset;
1255
1256	if (var->vmode & FB_VMODE_YWRAP)
1257		info->var.vmode |= FB_VMODE_YWRAP;
1258	else
1259		info->var.vmode &= ~FB_VMODE_YWRAP;
1260
1261	fsl_diu_set_aoi(info);
1262
1263	return 0;
1264}
1265
1266static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
1267		       unsigned long arg)
1268{
1269	struct mfb_info *mfbi = info->par;
1270	struct diu_ad *ad = mfbi->ad;
1271	struct mfb_chroma_key ck;
1272	unsigned char global_alpha;
1273	struct aoi_display_offset aoi_d;
1274	__u32 pix_fmt;
1275	void __user *buf = (void __user *)arg;
1276
1277	if (!arg)
1278		return -EINVAL;
1279
1280	dev_dbg(info->dev, "ioctl %08x (dir=%s%s type=%u nr=%u size=%u)\n", cmd,
1281		_IOC_DIR(cmd) & _IOC_READ ? "R" : "",
1282		_IOC_DIR(cmd) & _IOC_WRITE ? "W" : "",
1283		_IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
1284
1285	switch (cmd) {
1286	case MFB_SET_PIXFMT_OLD:
1287		dev_warn(info->dev,
1288			 "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n",
1289			 MFB_SET_PIXFMT_OLD);
1290		fallthrough;
1291	case MFB_SET_PIXFMT:
1292		if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
1293			return -EFAULT;
1294		ad->pix_fmt = pix_fmt;
1295		break;
1296	case MFB_GET_PIXFMT_OLD:
1297		dev_warn(info->dev,
1298			 "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n",
1299			 MFB_GET_PIXFMT_OLD);
1300		fallthrough;
1301	case MFB_GET_PIXFMT:
1302		pix_fmt = ad->pix_fmt;
1303		if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
1304			return -EFAULT;
1305		break;
1306	case MFB_SET_AOID:
1307		if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
1308			return -EFAULT;
1309		mfbi->x_aoi_d = aoi_d.x_aoi_d;
1310		mfbi->y_aoi_d = aoi_d.y_aoi_d;
1311		fsl_diu_check_var(&info->var, info);
1312		fsl_diu_set_aoi(info);
1313		break;
1314	case MFB_GET_AOID:
1315		aoi_d.x_aoi_d = mfbi->x_aoi_d;
1316		aoi_d.y_aoi_d = mfbi->y_aoi_d;
1317		if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
1318			return -EFAULT;
1319		break;
1320	case MFB_GET_ALPHA:
1321		global_alpha = mfbi->g_alpha;
1322		if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
1323			return -EFAULT;
1324		break;
1325	case MFB_SET_ALPHA:
1326		/* set panel information */
1327		if (copy_from_user(&global_alpha, buf, sizeof(global_alpha)))
1328			return -EFAULT;
1329		ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
1330							(global_alpha & 0xff);
1331		mfbi->g_alpha = global_alpha;
1332		break;
1333	case MFB_SET_CHROMA_KEY:
1334		/* set panel winformation */
1335		if (copy_from_user(&ck, buf, sizeof(ck)))
1336			return -EFAULT;
1337
1338		if (ck.enable &&
1339		   (ck.red_max < ck.red_min ||
1340		    ck.green_max < ck.green_min ||
1341		    ck.blue_max < ck.blue_min))
1342			return -EINVAL;
1343
1344		if (!ck.enable) {
1345			ad->ckmax_r = 0;
1346			ad->ckmax_g = 0;
1347			ad->ckmax_b = 0;
1348			ad->ckmin_r = 255;
1349			ad->ckmin_g = 255;
1350			ad->ckmin_b = 255;
1351		} else {
1352			ad->ckmax_r = ck.red_max;
1353			ad->ckmax_g = ck.green_max;
1354			ad->ckmax_b = ck.blue_max;
1355			ad->ckmin_r = ck.red_min;
1356			ad->ckmin_g = ck.green_min;
1357			ad->ckmin_b = ck.blue_min;
1358		}
1359		break;
1360#ifdef CONFIG_PPC_MPC512x
1361	case MFB_SET_GAMMA: {
1362		struct fsl_diu_data *data = mfbi->parent;
1363
1364		if (copy_from_user(data->gamma, buf, sizeof(data->gamma)))
1365			return -EFAULT;
1366		setbits32(&data->diu_reg->gamma, 0); /* Force table reload */
1367		break;
1368	}
1369	case MFB_GET_GAMMA: {
1370		struct fsl_diu_data *data = mfbi->parent;
1371
1372		if (copy_to_user(buf, data->gamma, sizeof(data->gamma)))
1373			return -EFAULT;
1374		break;
1375	}
1376#endif
1377	default:
1378		dev_err(info->dev, "unknown ioctl command (0x%08X)\n", cmd);
1379		return -ENOIOCTLCMD;
1380	}
1381
1382	return 0;
1383}
1384
1385static inline void fsl_diu_enable_interrupts(struct fsl_diu_data *data)
1386{
1387	u32 int_mask = INT_UNDRUN; /* enable underrun detection */
1388
1389	if (IS_ENABLED(CONFIG_NOT_COHERENT_CACHE))
1390		int_mask |= INT_VSYNC; /* enable vertical sync */
1391
1392	clrbits32(&data->diu_reg->int_mask, int_mask);
1393}
1394
1395/* turn on fb if count == 1
1396 */
1397static int fsl_diu_open(struct fb_info *info, int user)
1398{
1399	struct mfb_info *mfbi = info->par;
1400	int res = 0;
1401
1402	/* free boot splash memory on first /dev/fb0 open */
1403	if ((mfbi->index == PLANE0) && diu_ops.release_bootmem)
1404		diu_ops.release_bootmem();
1405
1406	spin_lock(&diu_lock);
1407	mfbi->count++;
1408	if (mfbi->count == 1) {
1409		fsl_diu_check_var(&info->var, info);
1410		res = fsl_diu_set_par(info);
1411		if (res < 0)
1412			mfbi->count--;
1413		else {
1414			fsl_diu_enable_interrupts(mfbi->parent);
1415			fsl_diu_enable_panel(info);
1416		}
1417	}
1418
1419	spin_unlock(&diu_lock);
1420	return res;
1421}
1422
1423/* turn off fb if count == 0
1424 */
1425static int fsl_diu_release(struct fb_info *info, int user)
1426{
1427	struct mfb_info *mfbi = info->par;
1428	int res = 0;
1429
1430	spin_lock(&diu_lock);
1431	mfbi->count--;
1432	if (mfbi->count == 0) {
1433		struct fsl_diu_data *data = mfbi->parent;
1434		bool disable = true;
1435		int i;
1436
1437		/* Disable interrupts only if all AOIs are closed */
1438		for (i = 0; i < NUM_AOIS; i++) {
1439			struct mfb_info *mi = data->fsl_diu_info[i].par;
1440
1441			if (mi->count)
1442				disable = false;
1443		}
1444		if (disable)
1445			out_be32(&data->diu_reg->int_mask, 0xffffffff);
1446		fsl_diu_disable_panel(info);
1447	}
1448
1449	spin_unlock(&diu_lock);
1450	return res;
1451}
1452
1453static const struct fb_ops fsl_diu_ops = {
1454	.owner = THIS_MODULE,
1455	.fb_check_var = fsl_diu_check_var,
1456	.fb_set_par = fsl_diu_set_par,
1457	.fb_setcolreg = fsl_diu_setcolreg,
1458	.fb_pan_display = fsl_diu_pan_display,
1459	.fb_fillrect = cfb_fillrect,
1460	.fb_copyarea = cfb_copyarea,
1461	.fb_imageblit = cfb_imageblit,
1462	.fb_ioctl = fsl_diu_ioctl,
1463	.fb_open = fsl_diu_open,
1464	.fb_release = fsl_diu_release,
1465	.fb_cursor = fsl_diu_cursor,
1466};
1467
1468static int install_fb(struct fb_info *info)
1469{
1470	int rc;
1471	struct mfb_info *mfbi = info->par;
1472	struct fsl_diu_data *data = mfbi->parent;
1473	const char *aoi_mode, *init_aoi_mode = "320x240";
1474	struct fb_videomode *db = fsl_diu_mode_db;
1475	unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
1476	int has_default_mode = 1;
1477
1478	info->var.activate = FB_ACTIVATE_NOW;
1479	info->fbops = &fsl_diu_ops;
1480	info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK |
1481		FBINFO_READS_FAST;
1482	info->pseudo_palette = mfbi->pseudo_palette;
1483
1484	rc = fb_alloc_cmap(&info->cmap, 16, 0);
1485	if (rc)
1486		return rc;
1487
1488	if (mfbi->index == PLANE0) {
1489		if (data->has_edid) {
1490			/* Now build modedb from EDID */
1491			fb_edid_to_monspecs(data->edid_data, &info->monspecs);
1492			fb_videomode_to_modelist(info->monspecs.modedb,
1493						 info->monspecs.modedb_len,
1494						 &info->modelist);
1495			db = info->monspecs.modedb;
1496			dbsize = info->monspecs.modedb_len;
1497		}
1498		aoi_mode = fb_mode;
1499	} else {
1500		aoi_mode = init_aoi_mode;
1501	}
1502	rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, NULL,
1503			  default_bpp);
1504	if (!rc) {
1505		/*
1506		 * For plane 0 we continue and look into
1507		 * driver's internal modedb.
1508		 */
1509		if ((mfbi->index == PLANE0) && data->has_edid)
1510			has_default_mode = 0;
1511		else
1512			return -EINVAL;
1513	}
1514
1515	if (!has_default_mode) {
1516		rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
1517			ARRAY_SIZE(fsl_diu_mode_db), NULL, default_bpp);
1518		if (rc)
1519			has_default_mode = 1;
1520	}
1521
1522	/* Still not found, use preferred mode from database if any */
1523	if (!has_default_mode && info->monspecs.modedb) {
1524		struct fb_monspecs *specs = &info->monspecs;
1525		struct fb_videomode *modedb = &specs->modedb[0];
1526
1527		/*
1528		 * Get preferred timing. If not found,
1529		 * first mode in database will be used.
1530		 */
1531		if (specs->misc & FB_MISC_1ST_DETAIL) {
1532			int i;
1533
1534			for (i = 0; i < specs->modedb_len; i++) {
1535				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
1536					modedb = &specs->modedb[i];
1537					break;
1538				}
1539			}
1540		}
1541
1542		info->var.bits_per_pixel = default_bpp;
1543		fb_videomode_to_var(&info->var, modedb);
1544	}
1545
1546	if (fsl_diu_check_var(&info->var, info)) {
1547		dev_err(info->dev, "fsl_diu_check_var failed\n");
1548		unmap_video_memory(info);
1549		fb_dealloc_cmap(&info->cmap);
1550		return -EINVAL;
1551	}
1552
1553	if (register_framebuffer(info) < 0) {
1554		dev_err(info->dev, "register_framebuffer failed\n");
1555		unmap_video_memory(info);
1556		fb_dealloc_cmap(&info->cmap);
1557		return -EINVAL;
1558	}
1559
1560	mfbi->registered = 1;
1561	dev_info(info->dev, "%s registered successfully\n", mfbi->id);
1562
1563	return 0;
1564}
1565
1566static void uninstall_fb(struct fb_info *info)
1567{
1568	struct mfb_info *mfbi = info->par;
1569
1570	if (!mfbi->registered)
1571		return;
1572
1573	unregister_framebuffer(info);
1574	unmap_video_memory(info);
1575	fb_dealloc_cmap(&info->cmap);
1576
1577	mfbi->registered = 0;
1578}
1579
1580static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
1581{
1582	struct diu __iomem *hw = dev_id;
1583	uint32_t status = in_be32(&hw->int_status);
1584
1585	if (status) {
1586		/* This is the workaround for underrun */
1587		if (status & INT_UNDRUN) {
1588			out_be32(&hw->diu_mode, 0);
1589			udelay(1);
1590			out_be32(&hw->diu_mode, 1);
1591		}
1592#if defined(CONFIG_NOT_COHERENT_CACHE)
1593		else if (status & INT_VSYNC) {
1594			unsigned int i;
1595
1596			for (i = 0; i < coherence_data_size;
1597				i += d_cache_line_size)
1598				__asm__ __volatile__ (
1599					"dcbz 0, %[input]"
1600				::[input]"r"(&coherence_data[i]));
1601		}
1602#endif
1603		return IRQ_HANDLED;
1604	}
1605	return IRQ_NONE;
1606}
1607
1608#ifdef CONFIG_PM
1609/*
1610 * Power management hooks. Note that we won't be called from IRQ context,
1611 * unlike the blank functions above, so we may sleep.
1612 */
1613static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
1614{
1615	struct fsl_diu_data *data;
1616
1617	data = dev_get_drvdata(&ofdev->dev);
1618	disable_lcdc(data->fsl_diu_info);
1619
1620	return 0;
1621}
1622
1623static int fsl_diu_resume(struct platform_device *ofdev)
1624{
1625	struct fsl_diu_data *data;
1626	unsigned int i;
1627
1628	data = dev_get_drvdata(&ofdev->dev);
1629
1630	fsl_diu_enable_interrupts(data);
1631	update_lcdc(data->fsl_diu_info);
1632	for (i = 0; i < NUM_AOIS; i++) {
1633		if (data->mfb[i].count)
1634			fsl_diu_enable_panel(&data->fsl_diu_info[i]);
1635	}
1636
1637	return 0;
1638}
1639
1640#else
1641#define fsl_diu_suspend NULL
1642#define fsl_diu_resume NULL
1643#endif				/* CONFIG_PM */
1644
1645static ssize_t store_monitor(struct device *device,
1646	struct device_attribute *attr, const char *buf, size_t count)
1647{
1648	enum fsl_diu_monitor_port old_monitor_port;
1649	struct fsl_diu_data *data =
1650		container_of(attr, struct fsl_diu_data, dev_attr);
1651
1652	old_monitor_port = data->monitor_port;
1653	data->monitor_port = fsl_diu_name_to_port(buf);
1654
1655	if (old_monitor_port != data->monitor_port) {
1656		/* All AOIs need adjust pixel format
1657		 * fsl_diu_set_par only change the pixsel format here
1658		 * unlikely to fail. */
1659		unsigned int i;
1660
1661		for (i=0; i < NUM_AOIS; i++)
1662			fsl_diu_set_par(&data->fsl_diu_info[i]);
1663	}
1664	return count;
1665}
1666
1667static ssize_t show_monitor(struct device *device,
1668	struct device_attribute *attr, char *buf)
1669{
1670	struct fsl_diu_data *data =
1671		container_of(attr, struct fsl_diu_data, dev_attr);
1672
1673	switch (data->monitor_port) {
1674	case FSL_DIU_PORT_DVI:
1675		return sprintf(buf, "DVI\n");
1676	case FSL_DIU_PORT_LVDS:
1677		return sprintf(buf, "Single-link LVDS\n");
1678	case FSL_DIU_PORT_DLVDS:
1679		return sprintf(buf, "Dual-link LVDS\n");
1680	}
1681
1682	return 0;
1683}
1684
1685static int fsl_diu_probe(struct platform_device *pdev)
1686{
1687	struct device_node *np = pdev->dev.of_node;
1688	struct mfb_info *mfbi;
1689	struct fsl_diu_data *data;
1690	dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */
1691	const void *prop;
1692	unsigned int i;
1693	int ret;
1694
1695	data = dmam_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
1696				   &dma_addr, GFP_DMA | __GFP_ZERO);
1697	if (!data)
1698		return -ENOMEM;
1699	data->dma_addr = dma_addr;
1700
1701	/*
1702	 * dma_alloc_coherent() uses a page allocator, so the address is
1703	 * always page-aligned.  We need the memory to be 32-byte aligned,
1704	 * so that's good.  However, if one day the allocator changes, we
1705	 * need to catch that.  It's not worth the effort to handle unaligned
1706	 * alloctions now because it's highly unlikely to ever be a problem.
1707	 */
1708	if ((unsigned long)data & 31) {
1709		dev_err(&pdev->dev, "misaligned allocation");
1710		ret = -ENOMEM;
1711		goto error;
1712	}
1713
1714	spin_lock_init(&data->reg_lock);
1715
1716	for (i = 0; i < NUM_AOIS; i++) {
1717		struct fb_info *info = &data->fsl_diu_info[i];
1718
1719		info->device = &pdev->dev;
1720		info->par = &data->mfb[i];
1721
1722		/*
1723		 * We store the physical address of the AD in the reserved
1724		 * 'paddr' field of the AD itself.
1725		 */
1726		data->ad[i].paddr = DMA_ADDR(data, ad[i]);
1727
1728		info->fix.smem_start = 0;
1729
1730		/* Initialize the AOI data structure */
1731		mfbi = info->par;
1732		memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
1733		mfbi->parent = data;
1734		mfbi->ad = &data->ad[i];
1735	}
1736
1737	/* Get the EDID data from the device tree, if present */
1738	prop = of_get_property(np, "edid", &ret);
1739	if (prop && ret == EDID_LENGTH) {
1740		memcpy(data->edid_data, prop, EDID_LENGTH);
1741		data->has_edid = true;
1742	}
1743
1744	data->diu_reg = of_iomap(np, 0);
1745	if (!data->diu_reg) {
1746		dev_err(&pdev->dev, "cannot map DIU registers\n");
1747		ret = -EFAULT;
1748		goto error;
1749	}
1750
1751	/* Get the IRQ of the DIU */
1752	data->irq = irq_of_parse_and_map(np, 0);
1753
1754	if (!data->irq) {
1755		dev_err(&pdev->dev, "could not get DIU IRQ\n");
1756		ret = -EINVAL;
1757		goto error;
1758	}
1759	data->monitor_port = monitor_port;
1760
1761	/* Initialize the dummy Area Descriptor */
1762	data->dummy_ad.addr = cpu_to_le32(DMA_ADDR(data, dummy_aoi));
1763	data->dummy_ad.pix_fmt = 0x88882317;
1764	data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
1765	data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) |  2);
1766	data->dummy_ad.offset_xyi = 0;
1767	data->dummy_ad.offset_xyd = 0;
1768	data->dummy_ad.next_ad = 0;
1769	data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad);
1770
1771	/*
1772	 * Let DIU continue to display splash screen if it was pre-initialized
1773	 * by the bootloader; otherwise, clear the display.
1774	 */
1775	if (in_be32(&data->diu_reg->diu_mode) == MFB_MODE0)
1776		out_be32(&data->diu_reg->desc[0], 0);
1777
1778	out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr);
1779	out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr);
1780
1781	/*
1782	 * Older versions of U-Boot leave interrupts enabled, so disable
1783	 * all of them and clear the status register.
1784	 */
1785	out_be32(&data->diu_reg->int_mask, 0xffffffff);
1786	in_be32(&data->diu_reg->int_status);
1787
1788	ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb",
1789			  data->diu_reg);
1790	if (ret) {
1791		dev_err(&pdev->dev, "could not claim irq\n");
1792		goto error;
1793	}
1794
1795	for (i = 0; i < NUM_AOIS; i++) {
1796		ret = install_fb(&data->fsl_diu_info[i]);
1797		if (ret) {
1798			dev_err(&pdev->dev, "could not register fb %d\n", i);
1799			free_irq(data->irq, data->diu_reg);
1800			goto error;
1801		}
1802	}
1803
1804	sysfs_attr_init(&data->dev_attr.attr);
1805	data->dev_attr.attr.name = "monitor";
1806	data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
1807	data->dev_attr.show = show_monitor;
1808	data->dev_attr.store = store_monitor;
1809	ret = device_create_file(&pdev->dev, &data->dev_attr);
1810	if (ret) {
1811		dev_err(&pdev->dev, "could not create sysfs file %s\n",
1812			data->dev_attr.attr.name);
1813	}
1814
1815	dev_set_drvdata(&pdev->dev, data);
1816	return 0;
1817
1818error:
1819	for (i = 0; i < NUM_AOIS; i++)
1820		uninstall_fb(&data->fsl_diu_info[i]);
1821
1822	iounmap(data->diu_reg);
1823
1824	return ret;
1825}
1826
1827static int fsl_diu_remove(struct platform_device *pdev)
1828{
1829	struct fsl_diu_data *data;
1830	int i;
1831
1832	data = dev_get_drvdata(&pdev->dev);
1833	disable_lcdc(&data->fsl_diu_info[0]);
1834
1835	free_irq(data->irq, data->diu_reg);
1836
1837	for (i = 0; i < NUM_AOIS; i++)
1838		uninstall_fb(&data->fsl_diu_info[i]);
1839
1840	iounmap(data->diu_reg);
1841
1842	return 0;
1843}
1844
1845#ifndef MODULE
1846static int __init fsl_diu_setup(char *options)
1847{
1848	char *opt;
1849	unsigned long val;
1850
1851	if (!options || !*options)
1852		return 0;
1853
1854	while ((opt = strsep(&options, ",")) != NULL) {
1855		if (!*opt)
1856			continue;
1857		if (!strncmp(opt, "monitor=", 8)) {
1858			monitor_port = fsl_diu_name_to_port(opt + 8);
1859		} else if (!strncmp(opt, "bpp=", 4)) {
1860			if (!kstrtoul(opt + 4, 10, &val))
1861				default_bpp = val;
1862		} else
1863			fb_mode = opt;
1864	}
1865
1866	return 0;
1867}
1868#endif
1869
1870static const struct of_device_id fsl_diu_match[] = {
1871#ifdef CONFIG_PPC_MPC512x
1872	{
1873		.compatible = "fsl,mpc5121-diu",
1874	},
1875#endif
1876	{
1877		.compatible = "fsl,diu",
1878	},
1879	{}
1880};
1881MODULE_DEVICE_TABLE(of, fsl_diu_match);
1882
1883static struct platform_driver fsl_diu_driver = {
1884	.driver = {
1885		.name = "fsl-diu-fb",
1886		.of_match_table = fsl_diu_match,
1887	},
1888	.probe  	= fsl_diu_probe,
1889	.remove 	= fsl_diu_remove,
1890	.suspend	= fsl_diu_suspend,
1891	.resume		= fsl_diu_resume,
1892};
1893
1894static int __init fsl_diu_init(void)
1895{
1896#ifdef CONFIG_NOT_COHERENT_CACHE
1897	struct device_node *np;
1898	const u32 *prop;
1899#endif
1900	int ret;
1901#ifndef MODULE
1902	char *option;
1903
1904	/*
1905	 * For kernel boot options (in 'video=xxxfb:<options>' format)
1906	 */
1907	if (fb_get_options("fslfb", &option))
1908		return -ENODEV;
1909	fsl_diu_setup(option);
1910#else
1911	monitor_port = fsl_diu_name_to_port(monitor_string);
1912#endif
1913
1914	/*
1915	 * Must to verify set_pixel_clock. If not implement on platform,
1916	 * then that means that there is no platform support for the DIU.
1917	 */
1918	if (!diu_ops.set_pixel_clock)
1919		return -ENODEV;
1920
1921	pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
1922
1923#ifdef CONFIG_NOT_COHERENT_CACHE
1924	np = of_get_cpu_node(0, NULL);
1925	if (!np) {
1926		pr_err("fsl-diu-fb: can't find 'cpu' device node\n");
1927		return -ENODEV;
1928	}
1929
1930	prop = of_get_property(np, "d-cache-size", NULL);
1931	if (prop == NULL) {
1932		pr_err("fsl-diu-fb: missing 'd-cache-size' property' "
1933		       "in 'cpu' node\n");
1934		of_node_put(np);
1935		return -ENODEV;
1936	}
1937
1938	/*
1939	 * Freescale PLRU requires 13/8 times the cache size to do a proper
1940	 * displacement flush
1941	 */
1942	coherence_data_size = be32_to_cpup(prop) * 13;
1943	coherence_data_size /= 8;
1944
1945	pr_debug("fsl-diu-fb: coherence data size is %zu bytes\n",
1946		 coherence_data_size);
1947
1948	prop = of_get_property(np, "d-cache-line-size", NULL);
1949	if (prop == NULL) {
1950		pr_err("fsl-diu-fb: missing 'd-cache-line-size' property' "
1951		       "in 'cpu' node\n");
1952		of_node_put(np);
1953		return -ENODEV;
1954	}
1955	d_cache_line_size = be32_to_cpup(prop);
1956
1957	pr_debug("fsl-diu-fb: cache lines size is %u bytes\n",
1958		 d_cache_line_size);
1959
1960	of_node_put(np);
1961	coherence_data = vmalloc(coherence_data_size);
1962	if (!coherence_data)
1963		return -ENOMEM;
1964#endif
1965
1966	ret = platform_driver_register(&fsl_diu_driver);
1967	if (ret) {
1968		pr_err("fsl-diu-fb: failed to register platform driver\n");
1969#if defined(CONFIG_NOT_COHERENT_CACHE)
1970		vfree(coherence_data);
1971#endif
1972	}
1973	return ret;
1974}
1975
1976static void __exit fsl_diu_exit(void)
1977{
1978	platform_driver_unregister(&fsl_diu_driver);
1979#if defined(CONFIG_NOT_COHERENT_CACHE)
1980	vfree(coherence_data);
1981#endif
1982}
1983
1984module_init(fsl_diu_init);
1985module_exit(fsl_diu_exit);
1986
1987MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
1988MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
1989MODULE_LICENSE("GPL");
1990
1991module_param_named(mode, fb_mode, charp, 0);
1992MODULE_PARM_DESC(mode,
1993	"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
1994module_param_named(bpp, default_bpp, ulong, 0);
1995MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified in 'mode'");
1996module_param_named(monitor, monitor_string, charp, 0);
1997MODULE_PARM_DESC(monitor, "Specify the monitor port "
1998	"(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");
1999
2000