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		fb_err(info, "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((__force const void *)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			fb_err(info, "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	fb_dbg(info, "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		fb_warn(info,
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		fb_warn(info,
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		fb_err(info, "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
1429	spin_lock(&diu_lock);
1430	mfbi->count--;
1431	if (mfbi->count == 0) {
1432		struct fsl_diu_data *data = mfbi->parent;
1433		bool disable = true;
1434		int i;
1435
1436		/* Disable interrupts only if all AOIs are closed */
1437		for (i = 0; i < NUM_AOIS; i++) {
1438			struct mfb_info *mi = data->fsl_diu_info[i].par;
1439
1440			if (mi->count)
1441				disable = false;
1442		}
1443		if (disable)
1444			out_be32(&data->diu_reg->int_mask, 0xffffffff);
1445		fsl_diu_disable_panel(info);
1446	}
1447
1448	spin_unlock(&diu_lock);
1449	return 0;
1450}
1451
1452static const struct fb_ops fsl_diu_ops = {
1453	.owner = THIS_MODULE,
1454	FB_DEFAULT_IOMEM_OPS,
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_ioctl = fsl_diu_ioctl,
1460	.fb_open = fsl_diu_open,
1461	.fb_release = fsl_diu_release,
1462	.fb_cursor = fsl_diu_cursor,
1463};
1464
1465static int install_fb(struct fb_info *info)
1466{
1467	int rc;
1468	struct mfb_info *mfbi = info->par;
1469	struct fsl_diu_data *data = mfbi->parent;
1470	const char *aoi_mode, *init_aoi_mode = "320x240";
1471	struct fb_videomode *db = fsl_diu_mode_db;
1472	unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
1473	int has_default_mode = 1;
1474
1475	info->var.activate = FB_ACTIVATE_NOW;
1476	info->fbops = &fsl_diu_ops;
1477	info->flags = FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK |
1478		FBINFO_READS_FAST;
1479	info->pseudo_palette = mfbi->pseudo_palette;
1480
1481	rc = fb_alloc_cmap(&info->cmap, 16, 0);
1482	if (rc)
1483		return rc;
1484
1485	if (mfbi->index == PLANE0) {
1486		if (data->has_edid) {
1487			/* Now build modedb from EDID */
1488			fb_edid_to_monspecs(data->edid_data, &info->monspecs);
1489			fb_videomode_to_modelist(info->monspecs.modedb,
1490						 info->monspecs.modedb_len,
1491						 &info->modelist);
1492			db = info->monspecs.modedb;
1493			dbsize = info->monspecs.modedb_len;
1494		}
1495		aoi_mode = fb_mode;
1496	} else {
1497		aoi_mode = init_aoi_mode;
1498	}
1499	rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, NULL,
1500			  default_bpp);
1501	if (!rc) {
1502		/*
1503		 * For plane 0 we continue and look into
1504		 * driver's internal modedb.
1505		 */
1506		if ((mfbi->index == PLANE0) && data->has_edid)
1507			has_default_mode = 0;
1508		else
1509			return -EINVAL;
1510	}
1511
1512	if (!has_default_mode) {
1513		rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
1514			ARRAY_SIZE(fsl_diu_mode_db), NULL, default_bpp);
1515		if (rc)
1516			has_default_mode = 1;
1517	}
1518
1519	/* Still not found, use preferred mode from database if any */
1520	if (!has_default_mode && info->monspecs.modedb) {
1521		struct fb_monspecs *specs = &info->monspecs;
1522		struct fb_videomode *modedb = &specs->modedb[0];
1523
1524		/*
1525		 * Get preferred timing. If not found,
1526		 * first mode in database will be used.
1527		 */
1528		if (specs->misc & FB_MISC_1ST_DETAIL) {
1529			int i;
1530
1531			for (i = 0; i < specs->modedb_len; i++) {
1532				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
1533					modedb = &specs->modedb[i];
1534					break;
1535				}
1536			}
1537		}
1538
1539		info->var.bits_per_pixel = default_bpp;
1540		fb_videomode_to_var(&info->var, modedb);
1541	}
1542
1543	if (fsl_diu_check_var(&info->var, info)) {
1544		fb_err(info, "fsl_diu_check_var failed\n");
1545		unmap_video_memory(info);
1546		fb_dealloc_cmap(&info->cmap);
1547		return -EINVAL;
1548	}
1549
1550	if (register_framebuffer(info) < 0) {
1551		fb_err(info, "register_framebuffer failed\n");
1552		unmap_video_memory(info);
1553		fb_dealloc_cmap(&info->cmap);
1554		return -EINVAL;
1555	}
1556
1557	mfbi->registered = 1;
1558	fb_info(info, "%s registered successfully\n", mfbi->id);
1559
1560	return 0;
1561}
1562
1563static void uninstall_fb(struct fb_info *info)
1564{
1565	struct mfb_info *mfbi = info->par;
1566
1567	if (!mfbi->registered)
1568		return;
1569
1570	unregister_framebuffer(info);
1571	unmap_video_memory(info);
1572	fb_dealloc_cmap(&info->cmap);
1573
1574	mfbi->registered = 0;
1575}
1576
1577static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
1578{
1579	struct diu __iomem *hw = dev_id;
1580	uint32_t status = in_be32(&hw->int_status);
1581
1582	if (status) {
1583		/* This is the workaround for underrun */
1584		if (status & INT_UNDRUN) {
1585			out_be32(&hw->diu_mode, 0);
1586			udelay(1);
1587			out_be32(&hw->diu_mode, 1);
1588		}
1589#if defined(CONFIG_NOT_COHERENT_CACHE)
1590		else if (status & INT_VSYNC) {
1591			unsigned int i;
1592
1593			for (i = 0; i < coherence_data_size;
1594				i += d_cache_line_size)
1595				__asm__ __volatile__ (
1596					"dcbz 0, %[input]"
1597				::[input]"r"(&coherence_data[i]));
1598		}
1599#endif
1600		return IRQ_HANDLED;
1601	}
1602	return IRQ_NONE;
1603}
1604
1605#ifdef CONFIG_PM
1606/*
1607 * Power management hooks. Note that we won't be called from IRQ context,
1608 * unlike the blank functions above, so we may sleep.
1609 */
1610static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
1611{
1612	struct fsl_diu_data *data;
1613
1614	data = dev_get_drvdata(&ofdev->dev);
1615	disable_lcdc(data->fsl_diu_info);
1616
1617	return 0;
1618}
1619
1620static int fsl_diu_resume(struct platform_device *ofdev)
1621{
1622	struct fsl_diu_data *data;
1623	unsigned int i;
1624
1625	data = dev_get_drvdata(&ofdev->dev);
1626
1627	fsl_diu_enable_interrupts(data);
1628	update_lcdc(data->fsl_diu_info);
1629	for (i = 0; i < NUM_AOIS; i++) {
1630		if (data->mfb[i].count)
1631			fsl_diu_enable_panel(&data->fsl_diu_info[i]);
1632	}
1633
1634	return 0;
1635}
1636
1637#else
1638#define fsl_diu_suspend NULL
1639#define fsl_diu_resume NULL
1640#endif				/* CONFIG_PM */
1641
1642static ssize_t store_monitor(struct device *device,
1643	struct device_attribute *attr, const char *buf, size_t count)
1644{
1645	enum fsl_diu_monitor_port old_monitor_port;
1646	struct fsl_diu_data *data =
1647		container_of(attr, struct fsl_diu_data, dev_attr);
1648
1649	old_monitor_port = data->monitor_port;
1650	data->monitor_port = fsl_diu_name_to_port(buf);
1651
1652	if (old_monitor_port != data->monitor_port) {
1653		/* All AOIs need adjust pixel format
1654		 * fsl_diu_set_par only change the pixsel format here
1655		 * unlikely to fail. */
1656		unsigned int i;
1657
1658		for (i=0; i < NUM_AOIS; i++)
1659			fsl_diu_set_par(&data->fsl_diu_info[i]);
1660	}
1661	return count;
1662}
1663
1664static ssize_t show_monitor(struct device *device,
1665	struct device_attribute *attr, char *buf)
1666{
1667	struct fsl_diu_data *data =
1668		container_of(attr, struct fsl_diu_data, dev_attr);
1669
1670	switch (data->monitor_port) {
1671	case FSL_DIU_PORT_DVI:
1672		return sprintf(buf, "DVI\n");
1673	case FSL_DIU_PORT_LVDS:
1674		return sprintf(buf, "Single-link LVDS\n");
1675	case FSL_DIU_PORT_DLVDS:
1676		return sprintf(buf, "Dual-link LVDS\n");
1677	}
1678
1679	return 0;
1680}
1681
1682static int fsl_diu_probe(struct platform_device *pdev)
1683{
1684	struct device_node *np = pdev->dev.of_node;
1685	struct mfb_info *mfbi;
1686	struct fsl_diu_data *data;
1687	dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */
1688	const void *prop;
1689	unsigned int i;
1690	int ret;
1691
1692	data = dmam_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
1693				   &dma_addr, GFP_DMA | __GFP_ZERO);
1694	if (!data)
1695		return -ENOMEM;
1696	data->dma_addr = dma_addr;
1697
1698	/*
1699	 * dma_alloc_coherent() uses a page allocator, so the address is
1700	 * always page-aligned.  We need the memory to be 32-byte aligned,
1701	 * so that's good.  However, if one day the allocator changes, we
1702	 * need to catch that.  It's not worth the effort to handle unaligned
1703	 * alloctions now because it's highly unlikely to ever be a problem.
1704	 */
1705	if ((unsigned long)data & 31) {
1706		dev_err(&pdev->dev, "misaligned allocation");
1707		ret = -ENOMEM;
1708		goto error;
1709	}
1710
1711	spin_lock_init(&data->reg_lock);
1712
1713	for (i = 0; i < NUM_AOIS; i++) {
1714		struct fb_info *info = &data->fsl_diu_info[i];
1715
1716		info->device = &pdev->dev;
1717		info->par = &data->mfb[i];
1718
1719		/*
1720		 * We store the physical address of the AD in the reserved
1721		 * 'paddr' field of the AD itself.
1722		 */
1723		data->ad[i].paddr = DMA_ADDR(data, ad[i]);
1724
1725		info->fix.smem_start = 0;
1726
1727		/* Initialize the AOI data structure */
1728		mfbi = info->par;
1729		memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
1730		mfbi->parent = data;
1731		mfbi->ad = &data->ad[i];
1732	}
1733
1734	/* Get the EDID data from the device tree, if present */
1735	prop = of_get_property(np, "edid", &ret);
1736	if (prop && ret == EDID_LENGTH) {
1737		memcpy(data->edid_data, prop, EDID_LENGTH);
1738		data->has_edid = true;
1739	}
1740
1741	data->diu_reg = of_iomap(np, 0);
1742	if (!data->diu_reg) {
1743		dev_err(&pdev->dev, "cannot map DIU registers\n");
1744		ret = -EFAULT;
1745		goto error;
1746	}
1747
1748	/* Get the IRQ of the DIU */
1749	data->irq = irq_of_parse_and_map(np, 0);
1750
1751	if (!data->irq) {
1752		dev_err(&pdev->dev, "could not get DIU IRQ\n");
1753		ret = -EINVAL;
1754		goto error;
1755	}
1756	data->monitor_port = monitor_port;
1757
1758	/* Initialize the dummy Area Descriptor */
1759	data->dummy_ad.addr = cpu_to_le32(DMA_ADDR(data, dummy_aoi));
1760	data->dummy_ad.pix_fmt = 0x88882317;
1761	data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
1762	data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) |  2);
1763	data->dummy_ad.offset_xyi = 0;
1764	data->dummy_ad.offset_xyd = 0;
1765	data->dummy_ad.next_ad = 0;
1766	data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad);
1767
1768	/*
1769	 * Let DIU continue to display splash screen if it was pre-initialized
1770	 * by the bootloader; otherwise, clear the display.
1771	 */
1772	if (in_be32(&data->diu_reg->diu_mode) == MFB_MODE0)
1773		out_be32(&data->diu_reg->desc[0], 0);
1774
1775	out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr);
1776	out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr);
1777
1778	/*
1779	 * Older versions of U-Boot leave interrupts enabled, so disable
1780	 * all of them and clear the status register.
1781	 */
1782	out_be32(&data->diu_reg->int_mask, 0xffffffff);
1783	in_be32(&data->diu_reg->int_status);
1784
1785	ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb",
1786			  data->diu_reg);
1787	if (ret) {
1788		dev_err(&pdev->dev, "could not claim irq\n");
1789		goto error;
1790	}
1791
1792	for (i = 0; i < NUM_AOIS; i++) {
1793		ret = install_fb(&data->fsl_diu_info[i]);
1794		if (ret) {
1795			dev_err(&pdev->dev, "could not register fb %d\n", i);
1796			free_irq(data->irq, data->diu_reg);
1797			goto error;
1798		}
1799	}
1800
1801	sysfs_attr_init(&data->dev_attr.attr);
1802	data->dev_attr.attr.name = "monitor";
1803	data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
1804	data->dev_attr.show = show_monitor;
1805	data->dev_attr.store = store_monitor;
1806	ret = device_create_file(&pdev->dev, &data->dev_attr);
1807	if (ret) {
1808		dev_err(&pdev->dev, "could not create sysfs file %s\n",
1809			data->dev_attr.attr.name);
1810	}
1811
1812	dev_set_drvdata(&pdev->dev, data);
1813	return 0;
1814
1815error:
1816	for (i = 0; i < NUM_AOIS; i++)
1817		uninstall_fb(&data->fsl_diu_info[i]);
1818
1819	iounmap(data->diu_reg);
1820
1821	return ret;
1822}
1823
1824static void fsl_diu_remove(struct platform_device *pdev)
1825{
1826	struct fsl_diu_data *data;
1827	int i;
1828
1829	data = dev_get_drvdata(&pdev->dev);
1830	disable_lcdc(&data->fsl_diu_info[0]);
1831
1832	free_irq(data->irq, data->diu_reg);
1833
1834	for (i = 0; i < NUM_AOIS; i++)
1835		uninstall_fb(&data->fsl_diu_info[i]);
1836
1837	iounmap(data->diu_reg);
1838}
1839
1840#ifndef MODULE
1841static int __init fsl_diu_setup(char *options)
1842{
1843	char *opt;
1844	unsigned long val;
1845
1846	if (!options || !*options)
1847		return 0;
1848
1849	while ((opt = strsep(&options, ",")) != NULL) {
1850		if (!*opt)
1851			continue;
1852		if (!strncmp(opt, "monitor=", 8)) {
1853			monitor_port = fsl_diu_name_to_port(opt + 8);
1854		} else if (!strncmp(opt, "bpp=", 4)) {
1855			if (!kstrtoul(opt + 4, 10, &val))
1856				default_bpp = val;
1857		} else
1858			fb_mode = opt;
1859	}
1860
1861	return 0;
1862}
1863#endif
1864
1865static const struct of_device_id fsl_diu_match[] = {
1866#ifdef CONFIG_PPC_MPC512x
1867	{
1868		.compatible = "fsl,mpc5121-diu",
1869	},
1870#endif
1871	{
1872		.compatible = "fsl,diu",
1873	},
1874	{}
1875};
1876MODULE_DEVICE_TABLE(of, fsl_diu_match);
1877
1878static struct platform_driver fsl_diu_driver = {
1879	.driver = {
1880		.name = "fsl-diu-fb",
1881		.of_match_table = fsl_diu_match,
1882	},
1883	.probe  	= fsl_diu_probe,
1884	.remove_new 	= fsl_diu_remove,
1885	.suspend	= fsl_diu_suspend,
1886	.resume		= fsl_diu_resume,
1887};
1888
1889static int __init fsl_diu_init(void)
1890{
1891#ifdef CONFIG_NOT_COHERENT_CACHE
1892	struct device_node *np;
1893	const u32 *prop;
1894#endif
1895	int ret;
1896#ifndef MODULE
1897	char *option;
1898
1899	/*
1900	 * For kernel boot options (in 'video=xxxfb:<options>' format)
1901	 */
1902	if (fb_get_options("fslfb", &option))
1903		return -ENODEV;
1904	fsl_diu_setup(option);
1905#else
1906	monitor_port = fsl_diu_name_to_port(monitor_string);
1907#endif
1908
1909	/*
1910	 * Must to verify set_pixel_clock. If not implement on platform,
1911	 * then that means that there is no platform support for the DIU.
1912	 */
1913	if (!diu_ops.set_pixel_clock)
1914		return -ENODEV;
1915
1916	pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
1917
1918#ifdef CONFIG_NOT_COHERENT_CACHE
1919	np = of_get_cpu_node(0, NULL);
1920	if (!np) {
1921		pr_err("fsl-diu-fb: can't find 'cpu' device node\n");
1922		return -ENODEV;
1923	}
1924
1925	prop = of_get_property(np, "d-cache-size", NULL);
1926	if (prop == NULL) {
1927		pr_err("fsl-diu-fb: missing 'd-cache-size' property' "
1928		       "in 'cpu' node\n");
1929		of_node_put(np);
1930		return -ENODEV;
1931	}
1932
1933	/*
1934	 * Freescale PLRU requires 13/8 times the cache size to do a proper
1935	 * displacement flush
1936	 */
1937	coherence_data_size = be32_to_cpup(prop) * 13;
1938	coherence_data_size /= 8;
1939
1940	pr_debug("fsl-diu-fb: coherence data size is %zu bytes\n",
1941		 coherence_data_size);
1942
1943	prop = of_get_property(np, "d-cache-line-size", NULL);
1944	if (prop == NULL) {
1945		pr_err("fsl-diu-fb: missing 'd-cache-line-size' property' "
1946		       "in 'cpu' node\n");
1947		of_node_put(np);
1948		return -ENODEV;
1949	}
1950	d_cache_line_size = be32_to_cpup(prop);
1951
1952	pr_debug("fsl-diu-fb: cache lines size is %u bytes\n",
1953		 d_cache_line_size);
1954
1955	of_node_put(np);
1956	coherence_data = vmalloc(coherence_data_size);
1957	if (!coherence_data)
1958		return -ENOMEM;
1959#endif
1960
1961	ret = platform_driver_register(&fsl_diu_driver);
1962	if (ret) {
1963		pr_err("fsl-diu-fb: failed to register platform driver\n");
1964#if defined(CONFIG_NOT_COHERENT_CACHE)
1965		vfree(coherence_data);
1966#endif
1967	}
1968	return ret;
1969}
1970
1971static void __exit fsl_diu_exit(void)
1972{
1973	platform_driver_unregister(&fsl_diu_driver);
1974#if defined(CONFIG_NOT_COHERENT_CACHE)
1975	vfree(coherence_data);
1976#endif
1977}
1978
1979module_init(fsl_diu_init);
1980module_exit(fsl_diu_exit);
1981
1982MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
1983MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
1984MODULE_LICENSE("GPL");
1985
1986module_param_named(mode, fb_mode, charp, 0);
1987MODULE_PARM_DESC(mode,
1988	"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
1989module_param_named(bpp, default_bpp, ulong, 0);
1990MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified in 'mode'");
1991module_param_named(monitor, monitor_string, charp, 0);
1992MODULE_PARM_DESC(monitor, "Specify the monitor port "
1993	"(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");
1994
1995