File Index
Files and directories
Sign in
FILE

fsl-diu-fb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/fsl-diu-fb.c C
   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	strscpy_pad(fix->id, mfbi->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	device_remove_file(&pdev->dev, &data->dev_attr);
1831	disable_lcdc(&data->fsl_diu_info[0]);
1832
1833	free_irq(data->irq, data->diu_reg);
1834
1835	for (i = 0; i < NUM_AOIS; i++)
1836		uninstall_fb(&data->fsl_diu_info[i]);
1837
1838	iounmap(data->diu_reg);
1839}
1840
1841#ifndef MODULE
1842static int __init fsl_diu_setup(char *options)
1843{
1844	char *opt;
1845	unsigned long val;
1846
1847	if (!options || !*options)
1848		return 0;
1849
1850	while ((opt = strsep(&options, ",")) != NULL) {
1851		if (!*opt)
1852			continue;
1853		if (!strncmp(opt, "monitor=", 8)) {
1854			monitor_port = fsl_diu_name_to_port(opt + 8);
1855		} else if (!strncmp(opt, "bpp=", 4)) {
1856			if (!kstrtoul(opt + 4, 10, &val))
1857				default_bpp = val;
1858		} else
1859			fb_mode = opt;
1860	}
1861
1862	return 0;
1863}
1864#endif
1865
1866static const struct of_device_id fsl_diu_match[] = {
1867#ifdef CONFIG_PPC_MPC512x
1868	{
1869		.compatible = "fsl,mpc5121-diu",
1870	},
1871#endif
1872	{
1873		.compatible = "fsl,diu",
1874	},
1875	{}
1876};
1877MODULE_DEVICE_TABLE(of, fsl_diu_match);
1878
1879static struct platform_driver fsl_diu_driver = {
1880	.driver		= {
1881		.name = "fsl-diu-fb",
1882		.of_match_table = fsl_diu_match,
1883	},
1884	.probe		= fsl_diu_probe,
1885	.remove		= fsl_diu_remove,
1886	.suspend	= fsl_diu_suspend,
1887	.resume		= fsl_diu_resume,
1888};
1889
1890static int __init fsl_diu_init(void)
1891{
1892#ifdef CONFIG_NOT_COHERENT_CACHE
1893	struct device_node *np;
1894	const u32 *prop;
1895#endif
1896	int ret;
1897#ifndef MODULE
1898	char *option;
1899
1900	/*
1901	 * For kernel boot options (in 'video=xxxfb:<options>' format)
1902	 */
1903	if (fb_get_options("fslfb", &option))
1904		return -ENODEV;
1905	fsl_diu_setup(option);
1906#else
1907	monitor_port = fsl_diu_name_to_port(monitor_string);
1908#endif
1909
1910	/*
1911	 * Must to verify set_pixel_clock. If not implement on platform,
1912	 * then that means that there is no platform support for the DIU.
1913	 */
1914	if (!diu_ops.set_pixel_clock)
1915		return -ENODEV;
1916
1917	pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
1918
1919#ifdef CONFIG_NOT_COHERENT_CACHE
1920	np = of_get_cpu_node(0, NULL);
1921	if (!np) {
1922		pr_err("fsl-diu-fb: can't find 'cpu' device node\n");
1923		return -ENODEV;
1924	}
1925
1926	prop = of_get_property(np, "d-cache-size", NULL);
1927	if (prop == NULL) {
1928		pr_err("fsl-diu-fb: missing 'd-cache-size' property' "
1929		       "in 'cpu' node\n");
1930		of_node_put(np);
1931		return -ENODEV;
1932	}
1933
1934	/*
1935	 * Freescale PLRU requires 13/8 times the cache size to do a proper
1936	 * displacement flush
1937	 */
1938	coherence_data_size = be32_to_cpup(prop) * 13;
1939	coherence_data_size /= 8;
1940
1941	pr_debug("fsl-diu-fb: coherence data size is %zu bytes\n",
1942		 coherence_data_size);
1943
1944	prop = of_get_property(np, "d-cache-line-size", NULL);
1945	if (prop == NULL) {
1946		pr_err("fsl-diu-fb: missing 'd-cache-line-size' property' "
1947		       "in 'cpu' node\n");
1948		of_node_put(np);
1949		return -ENODEV;
1950	}
1951	d_cache_line_size = be32_to_cpup(prop);
1952
1953	pr_debug("fsl-diu-fb: cache lines size is %u bytes\n",
1954		 d_cache_line_size);
1955
1956	of_node_put(np);
1957	coherence_data = vmalloc(coherence_data_size);
1958	if (!coherence_data)
1959		return -ENOMEM;
1960#endif
1961
1962	ret = platform_driver_register(&fsl_diu_driver);
1963	if (ret) {
1964		pr_err("fsl-diu-fb: failed to register platform driver\n");
1965#if defined(CONFIG_NOT_COHERENT_CACHE)
1966		vfree(coherence_data);
1967#endif
1968	}
1969	return ret;
1970}
1971
1972static void __exit fsl_diu_exit(void)
1973{
1974	platform_driver_unregister(&fsl_diu_driver);
1975#if defined(CONFIG_NOT_COHERENT_CACHE)
1976	vfree(coherence_data);
1977#endif
1978}
1979
1980module_init(fsl_diu_init);
1981module_exit(fsl_diu_exit);
1982
1983MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
1984MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
1985MODULE_LICENSE("GPL");
1986
1987module_param_named(mode, fb_mode, charp, 0);
1988MODULE_PARM_DESC(mode,
1989	"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
1990module_param_named(bpp, default_bpp, ulong, 0);
1991MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified in 'mode'");
1992module_param_named(monitor, monitor_string, charp, 0);
1993MODULE_PARM_DESC(monitor, "Specify the monitor port "
1994	"(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");
1995
~/ Read-only file preview.