cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fsl-diu-fb.c (52714B)


      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 */
    493void wr_reg_wa(u32 *reg, u32 val)
    494{
    495	do {
    496		out_be32(reg, val);
    497	} while (in_be32(reg) != val);
    498}
    499
    500static void fsl_diu_enable_panel(struct fb_info *info)
    501{
    502	struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
    503	struct diu_ad *ad = mfbi->ad;
    504	struct fsl_diu_data *data = mfbi->parent;
    505	struct diu __iomem *hw = data->diu_reg;
    506
    507	switch (mfbi->index) {
    508	case PLANE0:
    509		wr_reg_wa(&hw->desc[0], ad->paddr);
    510		break;
    511	case PLANE1_AOI0:
    512		cmfbi = &data->mfb[2];
    513		if (hw->desc[1] != ad->paddr) {	/* AOI0 closed */
    514			if (cmfbi->count > 0)	/* AOI1 open */
    515				ad->next_ad =
    516					cpu_to_le32(cmfbi->ad->paddr);
    517			else
    518				ad->next_ad = 0;
    519			wr_reg_wa(&hw->desc[1], ad->paddr);
    520		}
    521		break;
    522	case PLANE2_AOI0:
    523		cmfbi = &data->mfb[4];
    524		if (hw->desc[2] != ad->paddr) {	/* AOI0 closed */
    525			if (cmfbi->count > 0)	/* AOI1 open */
    526				ad->next_ad =
    527					cpu_to_le32(cmfbi->ad->paddr);
    528			else
    529				ad->next_ad = 0;
    530			wr_reg_wa(&hw->desc[2], ad->paddr);
    531		}
    532		break;
    533	case PLANE1_AOI1:
    534		pmfbi = &data->mfb[1];
    535		ad->next_ad = 0;
    536		if (hw->desc[1] == data->dummy_ad.paddr)
    537			wr_reg_wa(&hw->desc[1], ad->paddr);
    538		else					/* AOI0 open */
    539			pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
    540		break;
    541	case PLANE2_AOI1:
    542		pmfbi = &data->mfb[3];
    543		ad->next_ad = 0;
    544		if (hw->desc[2] == data->dummy_ad.paddr)
    545			wr_reg_wa(&hw->desc[2], ad->paddr);
    546		else				/* AOI0 was open */
    547			pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
    548		break;
    549	}
    550}
    551
    552static void fsl_diu_disable_panel(struct fb_info *info)
    553{
    554	struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
    555	struct diu_ad *ad = mfbi->ad;
    556	struct fsl_diu_data *data = mfbi->parent;
    557	struct diu __iomem *hw = data->diu_reg;
    558
    559	switch (mfbi->index) {
    560	case PLANE0:
    561		wr_reg_wa(&hw->desc[0], 0);
    562		break;
    563	case PLANE1_AOI0:
    564		cmfbi = &data->mfb[2];
    565		if (cmfbi->count > 0)	/* AOI1 is open */
    566			wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
    567					/* move AOI1 to the first */
    568		else			/* AOI1 was closed */
    569			wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
    570					/* close AOI 0 */
    571		break;
    572	case PLANE2_AOI0:
    573		cmfbi = &data->mfb[4];
    574		if (cmfbi->count > 0)	/* AOI1 is open */
    575			wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
    576					/* move AOI1 to the first */
    577		else			/* AOI1 was closed */
    578			wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
    579					/* close AOI 0 */
    580		break;
    581	case PLANE1_AOI1:
    582		pmfbi = &data->mfb[1];
    583		if (hw->desc[1] != ad->paddr) {
    584				/* AOI1 is not the first in the chain */
    585			if (pmfbi->count > 0)
    586					/* AOI0 is open, must be the first */
    587				pmfbi->ad->next_ad = 0;
    588		} else			/* AOI1 is the first in the chain */
    589			wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
    590					/* close AOI 1 */
    591		break;
    592	case PLANE2_AOI1:
    593		pmfbi = &data->mfb[3];
    594		if (hw->desc[2] != ad->paddr) {
    595				/* AOI1 is not the first in the chain */
    596			if (pmfbi->count > 0)
    597				/* AOI0 is open, must be the first */
    598				pmfbi->ad->next_ad = 0;
    599		} else		/* AOI1 is the first in the chain */
    600			wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
    601				/* close AOI 1 */
    602		break;
    603	}
    604}
    605
    606static void enable_lcdc(struct fb_info *info)
    607{
    608	struct mfb_info *mfbi = info->par;
    609	struct fsl_diu_data *data = mfbi->parent;
    610	struct diu __iomem *hw = data->diu_reg;
    611
    612	out_be32(&hw->diu_mode, MFB_MODE1);
    613}
    614
    615static void disable_lcdc(struct fb_info *info)
    616{
    617	struct mfb_info *mfbi = info->par;
    618	struct fsl_diu_data *data = mfbi->parent;
    619	struct diu __iomem *hw = data->diu_reg;
    620
    621	out_be32(&hw->diu_mode, 0);
    622}
    623
    624static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
    625				struct fb_info *info)
    626{
    627	struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
    628	struct fsl_diu_data *data = mfbi->parent;
    629	int available_height, upper_aoi_bottom;
    630	enum mfb_index index = mfbi->index;
    631	int lower_aoi_is_open, upper_aoi_is_open;
    632	__u32 base_plane_width, base_plane_height, upper_aoi_height;
    633
    634	base_plane_width = data->fsl_diu_info[0].var.xres;
    635	base_plane_height = data->fsl_diu_info[0].var.yres;
    636
    637	if (mfbi->x_aoi_d < 0)
    638		mfbi->x_aoi_d = 0;
    639	if (mfbi->y_aoi_d < 0)
    640		mfbi->y_aoi_d = 0;
    641	switch (index) {
    642	case PLANE0:
    643		if (mfbi->x_aoi_d != 0)
    644			mfbi->x_aoi_d = 0;
    645		if (mfbi->y_aoi_d != 0)
    646			mfbi->y_aoi_d = 0;
    647		break;
    648	case PLANE1_AOI0:
    649	case PLANE2_AOI0:
    650		lower_aoi_mfbi = data->fsl_diu_info[index+1].par;
    651		lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
    652		if (var->xres > base_plane_width)
    653			var->xres = base_plane_width;
    654		if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
    655			mfbi->x_aoi_d = base_plane_width - var->xres;
    656
    657		if (lower_aoi_is_open)
    658			available_height = lower_aoi_mfbi->y_aoi_d;
    659		else
    660			available_height = base_plane_height;
    661		if (var->yres > available_height)
    662			var->yres = available_height;
    663		if ((mfbi->y_aoi_d + var->yres) > available_height)
    664			mfbi->y_aoi_d = available_height - var->yres;
    665		break;
    666	case PLANE1_AOI1:
    667	case PLANE2_AOI1:
    668		upper_aoi_mfbi = data->fsl_diu_info[index-1].par;
    669		upper_aoi_height = data->fsl_diu_info[index-1].var.yres;
    670		upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
    671		upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
    672		if (var->xres > base_plane_width)
    673			var->xres = base_plane_width;
    674		if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
    675			mfbi->x_aoi_d = base_plane_width - var->xres;
    676		if (mfbi->y_aoi_d < 0)
    677			mfbi->y_aoi_d = 0;
    678		if (upper_aoi_is_open) {
    679			if (mfbi->y_aoi_d < upper_aoi_bottom)
    680				mfbi->y_aoi_d = upper_aoi_bottom;
    681			available_height = base_plane_height
    682						- upper_aoi_bottom;
    683		} else
    684			available_height = base_plane_height;
    685		if (var->yres > available_height)
    686			var->yres = available_height;
    687		if ((mfbi->y_aoi_d + var->yres) > base_plane_height)
    688			mfbi->y_aoi_d = base_plane_height - var->yres;
    689		break;
    690	}
    691}
    692/*
    693 * Checks to see if the hardware supports the state requested by var passed
    694 * in. This function does not alter the hardware state! If the var passed in
    695 * is slightly off by what the hardware can support then we alter the var
    696 * PASSED in to what we can do. If the hardware doesn't support mode change
    697 * a -EINVAL will be returned by the upper layers.
    698 */
    699static int fsl_diu_check_var(struct fb_var_screeninfo *var,
    700				struct fb_info *info)
    701{
    702	if (var->xres_virtual < var->xres)
    703		var->xres_virtual = var->xres;
    704	if (var->yres_virtual < var->yres)
    705		var->yres_virtual = var->yres;
    706
    707	if (var->xoffset + info->var.xres > info->var.xres_virtual)
    708		var->xoffset = info->var.xres_virtual - info->var.xres;
    709
    710	if (var->yoffset + info->var.yres > info->var.yres_virtual)
    711		var->yoffset = info->var.yres_virtual - info->var.yres;
    712
    713	if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
    714	    (var->bits_per_pixel != 16))
    715		var->bits_per_pixel = default_bpp;
    716
    717	switch (var->bits_per_pixel) {
    718	case 16:
    719		var->red.length = 5;
    720		var->red.offset = 11;
    721		var->red.msb_right = 0;
    722
    723		var->green.length = 6;
    724		var->green.offset = 5;
    725		var->green.msb_right = 0;
    726
    727		var->blue.length = 5;
    728		var->blue.offset = 0;
    729		var->blue.msb_right = 0;
    730
    731		var->transp.length = 0;
    732		var->transp.offset = 0;
    733		var->transp.msb_right = 0;
    734		break;
    735	case 24:
    736		var->red.length = 8;
    737		var->red.offset = 0;
    738		var->red.msb_right = 0;
    739
    740		var->green.length = 8;
    741		var->green.offset = 8;
    742		var->green.msb_right = 0;
    743
    744		var->blue.length = 8;
    745		var->blue.offset = 16;
    746		var->blue.msb_right = 0;
    747
    748		var->transp.length = 0;
    749		var->transp.offset = 0;
    750		var->transp.msb_right = 0;
    751		break;
    752	case 32:
    753		var->red.length = 8;
    754		var->red.offset = 16;
    755		var->red.msb_right = 0;
    756
    757		var->green.length = 8;
    758		var->green.offset = 8;
    759		var->green.msb_right = 0;
    760
    761		var->blue.length = 8;
    762		var->blue.offset = 0;
    763		var->blue.msb_right = 0;
    764
    765		var->transp.length = 8;
    766		var->transp.offset = 24;
    767		var->transp.msb_right = 0;
    768
    769		break;
    770	}
    771
    772	var->height = -1;
    773	var->width = -1;
    774	var->grayscale = 0;
    775
    776	/* Copy nonstd field to/from sync for fbset usage */
    777	var->sync |= var->nonstd;
    778	var->nonstd |= var->sync;
    779
    780	adjust_aoi_size_position(var, info);
    781	return 0;
    782}
    783
    784static void set_fix(struct fb_info *info)
    785{
    786	struct fb_fix_screeninfo *fix = &info->fix;
    787	struct fb_var_screeninfo *var = &info->var;
    788	struct mfb_info *mfbi = info->par;
    789
    790	strncpy(fix->id, mfbi->id, sizeof(fix->id));
    791	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
    792	fix->type = FB_TYPE_PACKED_PIXELS;
    793	fix->accel = FB_ACCEL_NONE;
    794	fix->visual = FB_VISUAL_TRUECOLOR;
    795	fix->xpanstep = 1;
    796	fix->ypanstep = 1;
    797}
    798
    799static void update_lcdc(struct fb_info *info)
    800{
    801	struct fb_var_screeninfo *var = &info->var;
    802	struct mfb_info *mfbi = info->par;
    803	struct fsl_diu_data *data = mfbi->parent;
    804	struct diu __iomem *hw;
    805	int i, j;
    806	u8 *gamma_table_base;
    807
    808	u32 temp;
    809
    810	hw = data->diu_reg;
    811
    812	if (diu_ops.set_monitor_port)
    813		diu_ops.set_monitor_port(data->monitor_port);
    814	gamma_table_base = data->gamma;
    815
    816	/* Prep for DIU init  - gamma table, cursor table */
    817
    818	for (i = 0; i <= 2; i++)
    819		for (j = 0; j <= 255; j++)
    820			*gamma_table_base++ = j;
    821
    822	if (diu_ops.set_gamma_table)
    823		diu_ops.set_gamma_table(data->monitor_port, data->gamma);
    824
    825	disable_lcdc(info);
    826
    827	/* Program DIU registers */
    828
    829	out_be32(&hw->gamma, DMA_ADDR(data, gamma));
    830
    831	out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */
    832	out_be32(&hw->disp_size, (var->yres << 16) | var->xres);
    833
    834	/* Horizontal and vertical configuration register */
    835	temp = var->left_margin << 22 | /* BP_H */
    836	       var->hsync_len << 11 |   /* PW_H */
    837	       var->right_margin;       /* FP_H */
    838
    839	out_be32(&hw->hsyn_para, temp);
    840
    841	temp = var->upper_margin << 22 | /* BP_V */
    842	       var->vsync_len << 11 |    /* PW_V  */
    843	       var->lower_margin;        /* FP_V  */
    844
    845	out_be32(&hw->vsyn_para, temp);
    846
    847	diu_ops.set_pixel_clock(var->pixclock);
    848
    849#ifndef CONFIG_PPC_MPC512x
    850	/*
    851	 * The PLUT register is defined differently on the MPC5121 than it
    852	 * is on other SOCs.  Unfortunately, there's no documentation that
    853	 * explains how it's supposed to be programmed, so for now, we leave
    854	 * it at the default value on the MPC5121.
    855	 *
    856	 * For other SOCs, program it for the highest priority, which will
    857	 * reduce the chance of underrun. Technically, we should scale the
    858	 * priority to match the screen resolution, but doing that properly
    859	 * requires delicate fine-tuning for each use-case.
    860	 */
    861	out_be32(&hw->plut, 0x01F5F666);
    862#endif
    863
    864	/* Enable the DIU */
    865	enable_lcdc(info);
    866}
    867
    868static int map_video_memory(struct fb_info *info)
    869{
    870	u32 smem_len = info->fix.line_length * info->var.yres_virtual;
    871	void *p;
    872
    873	p = alloc_pages_exact(smem_len, GFP_DMA | __GFP_ZERO);
    874	if (!p) {
    875		dev_err(info->dev, "unable to allocate fb memory\n");
    876		return -ENOMEM;
    877	}
    878	mutex_lock(&info->mm_lock);
    879	info->screen_base = p;
    880	info->fix.smem_start = virt_to_phys(info->screen_base);
    881	info->fix.smem_len = smem_len;
    882	mutex_unlock(&info->mm_lock);
    883	info->screen_size = info->fix.smem_len;
    884
    885	return 0;
    886}
    887
    888static void unmap_video_memory(struct fb_info *info)
    889{
    890	void *p = info->screen_base;
    891	size_t l = info->fix.smem_len;
    892
    893	mutex_lock(&info->mm_lock);
    894	info->screen_base = NULL;
    895	info->fix.smem_start = 0;
    896	info->fix.smem_len = 0;
    897	mutex_unlock(&info->mm_lock);
    898
    899	if (p)
    900		free_pages_exact(p, l);
    901}
    902
    903/*
    904 * Using the fb_var_screeninfo in fb_info we set the aoi of this
    905 * particular framebuffer. It is a light version of fsl_diu_set_par.
    906 */
    907static int fsl_diu_set_aoi(struct fb_info *info)
    908{
    909	struct fb_var_screeninfo *var = &info->var;
    910	struct mfb_info *mfbi = info->par;
    911	struct diu_ad *ad = mfbi->ad;
    912
    913	/* AOI should not be greater than display size */
    914	ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
    915	ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
    916	return 0;
    917}
    918
    919/**
    920 * fsl_diu_get_pixel_format: return the pixel format for a given color depth
    921 *
    922 * The pixel format is a 32-bit value that determine which bits in each
    923 * pixel are to be used for each color.  This is the default function used
    924 * if the platform does not define its own version.
    925 */
    926static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel)
    927{
    928#define PF_BYTE_F		0x10000000
    929#define PF_ALPHA_C_MASK		0x0E000000
    930#define PF_ALPHA_C_SHIFT	25
    931#define PF_BLUE_C_MASK		0x01800000
    932#define PF_BLUE_C_SHIFT		23
    933#define PF_GREEN_C_MASK		0x00600000
    934#define PF_GREEN_C_SHIFT	21
    935#define PF_RED_C_MASK		0x00180000
    936#define PF_RED_C_SHIFT		19
    937#define PF_PALETTE		0x00040000
    938#define PF_PIXEL_S_MASK		0x00030000
    939#define PF_PIXEL_S_SHIFT	16
    940#define PF_COMP_3_MASK		0x0000F000
    941#define PF_COMP_3_SHIFT		12
    942#define PF_COMP_2_MASK		0x00000F00
    943#define PF_COMP_2_SHIFT		8
    944#define PF_COMP_1_MASK		0x000000F0
    945#define PF_COMP_1_SHIFT		4
    946#define PF_COMP_0_MASK		0x0000000F
    947#define PF_COMP_0_SHIFT		0
    948
    949#define MAKE_PF(alpha, red, green, blue, size, c0, c1, c2, c3) \
    950	cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \
    951	(blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \
    952	(red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \
    953	(c2 << PF_COMP_2_SHIFT) | (c1 << PF_COMP_1_SHIFT) | \
    954	(c0 << PF_COMP_0_SHIFT) | (size << PF_PIXEL_S_SHIFT))
    955
    956	switch (bits_per_pixel) {
    957	case 32:
    958		/* 0x88883316 */
    959		return MAKE_PF(3, 2, 1, 0, 3, 8, 8, 8, 8);
    960	case 24:
    961		/* 0x88082219 */
    962		return MAKE_PF(4, 0, 1, 2, 2, 8, 8, 8, 0);
    963	case 16:
    964		/* 0x65053118 */
    965		return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0);
    966	default:
    967		pr_err("fsl-diu: unsupported color depth %u\n", bits_per_pixel);
    968		return 0;
    969	}
    970}
    971
    972/*
    973 * Copies a cursor image from user space to the proper place in driver
    974 * memory so that the hardware can display the cursor image.
    975 *
    976 * Cursor data is represented as a sequence of 'width' bits packed into bytes.
    977 * That is, the first 8 bits are in the first byte, the second 8 bits in the
    978 * second byte, and so on.  Therefore, the each row of the cursor is (width +
    979 * 7) / 8 bytes of 'data'
    980 *
    981 * The DIU only supports cursors up to 32x32 (MAX_CURS).  We reject cursors
    982 * larger than this, so we already know that 'width' <= 32.  Therefore, we can
    983 * simplify our code by using a 32-bit big-endian integer ("line") to read in
    984 * a single line of pixels, and only look at the top 'width' bits of that
    985 * integer.
    986 *
    987 * This could result in an unaligned 32-bit read.  For example, if the cursor
    988 * is 24x24, then the first three bytes of 'image' contain the pixel data for
    989 * the top line of the cursor.  We do a 32-bit read of 'image', but we look
    990 * only at the top 24 bits.  Then we increment 'image' by 3 bytes.  The next
    991 * read is unaligned.  The only problem is that we might read past the end of
    992 * 'image' by 1-3 bytes, but that should not cause any problems.
    993 */
    994static void fsl_diu_load_cursor_image(struct fb_info *info,
    995	const void *image, uint16_t bg, uint16_t fg,
    996	unsigned int width, unsigned int height)
    997{
    998	struct mfb_info *mfbi = info->par;
    999	struct fsl_diu_data *data = mfbi->parent;
   1000	__le16 *cursor = data->cursor;
   1001	__le16 _fg = cpu_to_le16(fg);
   1002	__le16 _bg = cpu_to_le16(bg);
   1003	unsigned int h, w;
   1004
   1005	for (h = 0; h < height; h++) {
   1006		uint32_t mask = 1 << 31;
   1007		uint32_t line = be32_to_cpup(image);
   1008
   1009		for (w = 0; w < width; w++) {
   1010			cursor[w] = (line & mask) ? _fg : _bg;
   1011			mask >>= 1;
   1012		}
   1013
   1014		cursor += MAX_CURS;
   1015		image += DIV_ROUND_UP(width, 8);
   1016	}
   1017}
   1018
   1019/*
   1020 * Set a hardware cursor.  The image data for the cursor is passed via the
   1021 * fb_cursor object.
   1022 */
   1023static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
   1024{
   1025	struct mfb_info *mfbi = info->par;
   1026	struct fsl_diu_data *data = mfbi->parent;
   1027	struct diu __iomem *hw = data->diu_reg;
   1028
   1029	if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
   1030		return -EINVAL;
   1031
   1032	/* The cursor size has changed */
   1033	if (cursor->set & FB_CUR_SETSIZE) {
   1034		/*
   1035		 * The DIU cursor is a fixed size, so when we get this
   1036		 * message, instead of resizing the cursor, we just clear
   1037		 * all the image data, in expectation of new data.  However,
   1038		 * in tests this control does not appear to be normally
   1039		 * called.
   1040		 */
   1041		memset(data->cursor, 0, sizeof(data->cursor));
   1042	}
   1043
   1044	/* The cursor position has changed (cursor->image.dx|dy) */
   1045	if (cursor->set & FB_CUR_SETPOS) {
   1046		uint32_t xx, yy;
   1047
   1048		yy = (cursor->image.dy - info->var.yoffset) & 0x7ff;
   1049		xx = (cursor->image.dx - info->var.xoffset) & 0x7ff;
   1050
   1051		out_be32(&hw->curs_pos, yy << 16 | xx);
   1052	}
   1053
   1054	/*
   1055	 * FB_CUR_SETIMAGE - the cursor image has changed
   1056	 * FB_CUR_SETCMAP  - the cursor colors has changed
   1057	 * FB_CUR_SETSHAPE - the cursor bitmask has changed
   1058	 */
   1059	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
   1060		/*
   1061		 * Determine the size of the cursor image data.  Normally,
   1062		 * it's 8x16.
   1063		 */
   1064		unsigned int image_size =
   1065			DIV_ROUND_UP(cursor->image.width, 8) *
   1066			cursor->image.height;
   1067		unsigned int image_words =
   1068			DIV_ROUND_UP(image_size, sizeof(uint32_t));
   1069		unsigned int bg_idx = cursor->image.bg_color;
   1070		unsigned int fg_idx = cursor->image.fg_color;
   1071		uint32_t *image, *source, *mask;
   1072		uint16_t fg, bg;
   1073		unsigned int i;
   1074
   1075		if (info->state != FBINFO_STATE_RUNNING)
   1076			return 0;
   1077
   1078		bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
   1079		     ((info->cmap.green[bg_idx] & 0xf8) << 2) |
   1080		     ((info->cmap.blue[bg_idx] & 0xf8) >> 3) |
   1081		     1 << 15;
   1082
   1083		fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
   1084		     ((info->cmap.green[fg_idx] & 0xf8) << 2) |
   1085		     ((info->cmap.blue[fg_idx] & 0xf8) >> 3) |
   1086		     1 << 15;
   1087
   1088		/* Use 32-bit operations on the data to improve performance */
   1089		image = (uint32_t *)data->next_cursor;
   1090		source = (uint32_t *)cursor->image.data;
   1091		mask = (uint32_t *)cursor->mask;
   1092
   1093		if (cursor->rop == ROP_XOR)
   1094			for (i = 0; i < image_words; i++)
   1095				image[i] = source[i] ^ mask[i];
   1096		else
   1097			for (i = 0; i < image_words; i++)
   1098				image[i] = source[i] & mask[i];
   1099
   1100		fsl_diu_load_cursor_image(info, image, bg, fg,
   1101			cursor->image.width, cursor->image.height);
   1102	}
   1103
   1104	/*
   1105	 * Show or hide the cursor.  The cursor data is always stored in the
   1106	 * 'cursor' memory block, and the actual cursor position is always in
   1107	 * the DIU's CURS_POS register.  To hide the cursor, we redirect the
   1108	 * CURSOR register to a blank cursor.  The show the cursor, we
   1109	 * redirect the CURSOR register to the real cursor data.
   1110	 */
   1111	if (cursor->enable)
   1112		out_be32(&hw->cursor, DMA_ADDR(data, cursor));
   1113	else
   1114		out_be32(&hw->cursor, DMA_ADDR(data, blank_cursor));
   1115
   1116	return 0;
   1117}
   1118
   1119/*
   1120 * Using the fb_var_screeninfo in fb_info we set the resolution of this
   1121 * particular framebuffer. This function alters the fb_fix_screeninfo stored
   1122 * in fb_info. It does not alter var in fb_info since we are using that
   1123 * data. This means we depend on the data in var inside fb_info to be
   1124 * supported by the hardware. fsl_diu_check_var is always called before
   1125 * fsl_diu_set_par to ensure this.
   1126 */
   1127static int fsl_diu_set_par(struct fb_info *info)
   1128{
   1129	unsigned long len;
   1130	struct fb_var_screeninfo *var = &info->var;
   1131	struct mfb_info *mfbi = info->par;
   1132	struct fsl_diu_data *data = mfbi->parent;
   1133	struct diu_ad *ad = mfbi->ad;
   1134	struct diu __iomem *hw;
   1135
   1136	hw = data->diu_reg;
   1137
   1138	set_fix(info);
   1139
   1140	len = info->var.yres_virtual * info->fix.line_length;
   1141	/* Alloc & dealloc each time resolution/bpp change */
   1142	if (len != info->fix.smem_len) {
   1143		if (info->fix.smem_start)
   1144			unmap_video_memory(info);
   1145
   1146		/* Memory allocation for framebuffer */
   1147		if (map_video_memory(info)) {
   1148			dev_err(info->dev, "unable to allocate fb memory 1\n");
   1149			return -ENOMEM;
   1150		}
   1151	}
   1152
   1153	if (diu_ops.get_pixel_format)
   1154		ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port,
   1155						       var->bits_per_pixel);
   1156	else
   1157		ad->pix_fmt = fsl_diu_get_pixel_format(var->bits_per_pixel);
   1158
   1159	ad->addr    = cpu_to_le32(info->fix.smem_start);
   1160	ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
   1161				var->xres_virtual) | mfbi->g_alpha;
   1162	/* AOI should not be greater than display size */
   1163	ad->aoi_size 	= cpu_to_le32((var->yres << 16) | var->xres);
   1164	ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
   1165	ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d);
   1166
   1167	/* Disable chroma keying function */
   1168	ad->ckmax_r = 0;
   1169	ad->ckmax_g = 0;
   1170	ad->ckmax_b = 0;
   1171
   1172	ad->ckmin_r = 255;
   1173	ad->ckmin_g = 255;
   1174	ad->ckmin_b = 255;
   1175
   1176	if (mfbi->index == PLANE0)
   1177		update_lcdc(info);
   1178	return 0;
   1179}
   1180
   1181static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
   1182{
   1183	return ((val << width) + 0x7FFF - val) >> 16;
   1184}
   1185
   1186/*
   1187 * Set a single color register. The values supplied have a 16 bit magnitude
   1188 * which needs to be scaled in this function for the hardware. Things to take
   1189 * into consideration are how many color registers, if any, are supported with
   1190 * the current color visual. With truecolor mode no color palettes are
   1191 * supported. Here a pseudo palette is created which we store the value in
   1192 * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited
   1193 * color palette.
   1194 */
   1195static int fsl_diu_setcolreg(unsigned int regno, unsigned int red,
   1196			     unsigned int green, unsigned int blue,
   1197			     unsigned int transp, struct fb_info *info)
   1198{
   1199	int ret = 1;
   1200
   1201	/*
   1202	 * If greyscale is true, then we convert the RGB value
   1203	 * to greyscale no matter what visual we are using.
   1204	 */
   1205	if (info->var.grayscale)
   1206		red = green = blue = (19595 * red + 38470 * green +
   1207				      7471 * blue) >> 16;
   1208	switch (info->fix.visual) {
   1209	case FB_VISUAL_TRUECOLOR:
   1210		/*
   1211		 * 16-bit True Colour.  We encode the RGB value
   1212		 * according to the RGB bitfield information.
   1213		 */
   1214		if (regno < 16) {
   1215			u32 *pal = info->pseudo_palette;
   1216			u32 v;
   1217
   1218			red = CNVT_TOHW(red, info->var.red.length);
   1219			green = CNVT_TOHW(green, info->var.green.length);
   1220			blue = CNVT_TOHW(blue, info->var.blue.length);
   1221			transp = CNVT_TOHW(transp, info->var.transp.length);
   1222
   1223			v = (red << info->var.red.offset) |
   1224			    (green << info->var.green.offset) |
   1225			    (blue << info->var.blue.offset) |
   1226			    (transp << info->var.transp.offset);
   1227
   1228			pal[regno] = v;
   1229			ret = 0;
   1230		}
   1231		break;
   1232	}
   1233
   1234	return ret;
   1235}
   1236
   1237/*
   1238 * Pan (or wrap, depending on the `vmode' field) the display using the
   1239 * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values
   1240 * don't fit, return -EINVAL.
   1241 */
   1242static int fsl_diu_pan_display(struct fb_var_screeninfo *var,
   1243			     struct fb_info *info)
   1244{
   1245	if ((info->var.xoffset == var->xoffset) &&
   1246	    (info->var.yoffset == var->yoffset))
   1247		return 0;	/* No change, do nothing */
   1248
   1249	if (var->xoffset + info->var.xres > info->var.xres_virtual
   1250	    || var->yoffset + info->var.yres > info->var.yres_virtual)
   1251		return -EINVAL;
   1252
   1253	info->var.xoffset = var->xoffset;
   1254	info->var.yoffset = var->yoffset;
   1255
   1256	if (var->vmode & FB_VMODE_YWRAP)
   1257		info->var.vmode |= FB_VMODE_YWRAP;
   1258	else
   1259		info->var.vmode &= ~FB_VMODE_YWRAP;
   1260
   1261	fsl_diu_set_aoi(info);
   1262
   1263	return 0;
   1264}
   1265
   1266static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd,
   1267		       unsigned long arg)
   1268{
   1269	struct mfb_info *mfbi = info->par;
   1270	struct diu_ad *ad = mfbi->ad;
   1271	struct mfb_chroma_key ck;
   1272	unsigned char global_alpha;
   1273	struct aoi_display_offset aoi_d;
   1274	__u32 pix_fmt;
   1275	void __user *buf = (void __user *)arg;
   1276
   1277	if (!arg)
   1278		return -EINVAL;
   1279
   1280	dev_dbg(info->dev, "ioctl %08x (dir=%s%s type=%u nr=%u size=%u)\n", cmd,
   1281		_IOC_DIR(cmd) & _IOC_READ ? "R" : "",
   1282		_IOC_DIR(cmd) & _IOC_WRITE ? "W" : "",
   1283		_IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
   1284
   1285	switch (cmd) {
   1286	case MFB_SET_PIXFMT_OLD:
   1287		dev_warn(info->dev,
   1288			 "MFB_SET_PIXFMT value of 0x%08x is deprecated.\n",
   1289			 MFB_SET_PIXFMT_OLD);
   1290		fallthrough;
   1291	case MFB_SET_PIXFMT:
   1292		if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt)))
   1293			return -EFAULT;
   1294		ad->pix_fmt = pix_fmt;
   1295		break;
   1296	case MFB_GET_PIXFMT_OLD:
   1297		dev_warn(info->dev,
   1298			 "MFB_GET_PIXFMT value of 0x%08x is deprecated.\n",
   1299			 MFB_GET_PIXFMT_OLD);
   1300		fallthrough;
   1301	case MFB_GET_PIXFMT:
   1302		pix_fmt = ad->pix_fmt;
   1303		if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt)))
   1304			return -EFAULT;
   1305		break;
   1306	case MFB_SET_AOID:
   1307		if (copy_from_user(&aoi_d, buf, sizeof(aoi_d)))
   1308			return -EFAULT;
   1309		mfbi->x_aoi_d = aoi_d.x_aoi_d;
   1310		mfbi->y_aoi_d = aoi_d.y_aoi_d;
   1311		fsl_diu_check_var(&info->var, info);
   1312		fsl_diu_set_aoi(info);
   1313		break;
   1314	case MFB_GET_AOID:
   1315		aoi_d.x_aoi_d = mfbi->x_aoi_d;
   1316		aoi_d.y_aoi_d = mfbi->y_aoi_d;
   1317		if (copy_to_user(buf, &aoi_d, sizeof(aoi_d)))
   1318			return -EFAULT;
   1319		break;
   1320	case MFB_GET_ALPHA:
   1321		global_alpha = mfbi->g_alpha;
   1322		if (copy_to_user(buf, &global_alpha, sizeof(global_alpha)))
   1323			return -EFAULT;
   1324		break;
   1325	case MFB_SET_ALPHA:
   1326		/* set panel information */
   1327		if (copy_from_user(&global_alpha, buf, sizeof(global_alpha)))
   1328			return -EFAULT;
   1329		ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) |
   1330							(global_alpha & 0xff);
   1331		mfbi->g_alpha = global_alpha;
   1332		break;
   1333	case MFB_SET_CHROMA_KEY:
   1334		/* set panel winformation */
   1335		if (copy_from_user(&ck, buf, sizeof(ck)))
   1336			return -EFAULT;
   1337
   1338		if (ck.enable &&
   1339		   (ck.red_max < ck.red_min ||
   1340		    ck.green_max < ck.green_min ||
   1341		    ck.blue_max < ck.blue_min))
   1342			return -EINVAL;
   1343
   1344		if (!ck.enable) {
   1345			ad->ckmax_r = 0;
   1346			ad->ckmax_g = 0;
   1347			ad->ckmax_b = 0;
   1348			ad->ckmin_r = 255;
   1349			ad->ckmin_g = 255;
   1350			ad->ckmin_b = 255;
   1351		} else {
   1352			ad->ckmax_r = ck.red_max;
   1353			ad->ckmax_g = ck.green_max;
   1354			ad->ckmax_b = ck.blue_max;
   1355			ad->ckmin_r = ck.red_min;
   1356			ad->ckmin_g = ck.green_min;
   1357			ad->ckmin_b = ck.blue_min;
   1358		}
   1359		break;
   1360#ifdef CONFIG_PPC_MPC512x
   1361	case MFB_SET_GAMMA: {
   1362		struct fsl_diu_data *data = mfbi->parent;
   1363
   1364		if (copy_from_user(data->gamma, buf, sizeof(data->gamma)))
   1365			return -EFAULT;
   1366		setbits32(&data->diu_reg->gamma, 0); /* Force table reload */
   1367		break;
   1368	}
   1369	case MFB_GET_GAMMA: {
   1370		struct fsl_diu_data *data = mfbi->parent;
   1371
   1372		if (copy_to_user(buf, data->gamma, sizeof(data->gamma)))
   1373			return -EFAULT;
   1374		break;
   1375	}
   1376#endif
   1377	default:
   1378		dev_err(info->dev, "unknown ioctl command (0x%08X)\n", cmd);
   1379		return -ENOIOCTLCMD;
   1380	}
   1381
   1382	return 0;
   1383}
   1384
   1385static inline void fsl_diu_enable_interrupts(struct fsl_diu_data *data)
   1386{
   1387	u32 int_mask = INT_UNDRUN; /* enable underrun detection */
   1388
   1389	if (IS_ENABLED(CONFIG_NOT_COHERENT_CACHE))
   1390		int_mask |= INT_VSYNC; /* enable vertical sync */
   1391
   1392	clrbits32(&data->diu_reg->int_mask, int_mask);
   1393}
   1394
   1395/* turn on fb if count == 1
   1396 */
   1397static int fsl_diu_open(struct fb_info *info, int user)
   1398{
   1399	struct mfb_info *mfbi = info->par;
   1400	int res = 0;
   1401
   1402	/* free boot splash memory on first /dev/fb0 open */
   1403	if ((mfbi->index == PLANE0) && diu_ops.release_bootmem)
   1404		diu_ops.release_bootmem();
   1405
   1406	spin_lock(&diu_lock);
   1407	mfbi->count++;
   1408	if (mfbi->count == 1) {
   1409		fsl_diu_check_var(&info->var, info);
   1410		res = fsl_diu_set_par(info);
   1411		if (res < 0)
   1412			mfbi->count--;
   1413		else {
   1414			fsl_diu_enable_interrupts(mfbi->parent);
   1415			fsl_diu_enable_panel(info);
   1416		}
   1417	}
   1418
   1419	spin_unlock(&diu_lock);
   1420	return res;
   1421}
   1422
   1423/* turn off fb if count == 0
   1424 */
   1425static int fsl_diu_release(struct fb_info *info, int user)
   1426{
   1427	struct mfb_info *mfbi = info->par;
   1428
   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_check_var = fsl_diu_check_var,
   1455	.fb_set_par = fsl_diu_set_par,
   1456	.fb_setcolreg = fsl_diu_setcolreg,
   1457	.fb_pan_display = fsl_diu_pan_display,
   1458	.fb_fillrect = cfb_fillrect,
   1459	.fb_copyarea = cfb_copyarea,
   1460	.fb_imageblit = cfb_imageblit,
   1461	.fb_ioctl = fsl_diu_ioctl,
   1462	.fb_open = fsl_diu_open,
   1463	.fb_release = fsl_diu_release,
   1464	.fb_cursor = fsl_diu_cursor,
   1465};
   1466
   1467static int install_fb(struct fb_info *info)
   1468{
   1469	int rc;
   1470	struct mfb_info *mfbi = info->par;
   1471	struct fsl_diu_data *data = mfbi->parent;
   1472	const char *aoi_mode, *init_aoi_mode = "320x240";
   1473	struct fb_videomode *db = fsl_diu_mode_db;
   1474	unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
   1475	int has_default_mode = 1;
   1476
   1477	info->var.activate = FB_ACTIVATE_NOW;
   1478	info->fbops = &fsl_diu_ops;
   1479	info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK |
   1480		FBINFO_READS_FAST;
   1481	info->pseudo_palette = mfbi->pseudo_palette;
   1482
   1483	rc = fb_alloc_cmap(&info->cmap, 16, 0);
   1484	if (rc)
   1485		return rc;
   1486
   1487	if (mfbi->index == PLANE0) {
   1488		if (data->has_edid) {
   1489			/* Now build modedb from EDID */
   1490			fb_edid_to_monspecs(data->edid_data, &info->monspecs);
   1491			fb_videomode_to_modelist(info->monspecs.modedb,
   1492						 info->monspecs.modedb_len,
   1493						 &info->modelist);
   1494			db = info->monspecs.modedb;
   1495			dbsize = info->monspecs.modedb_len;
   1496		}
   1497		aoi_mode = fb_mode;
   1498	} else {
   1499		aoi_mode = init_aoi_mode;
   1500	}
   1501	rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, NULL,
   1502			  default_bpp);
   1503	if (!rc) {
   1504		/*
   1505		 * For plane 0 we continue and look into
   1506		 * driver's internal modedb.
   1507		 */
   1508		if ((mfbi->index == PLANE0) && data->has_edid)
   1509			has_default_mode = 0;
   1510		else
   1511			return -EINVAL;
   1512	}
   1513
   1514	if (!has_default_mode) {
   1515		rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
   1516			ARRAY_SIZE(fsl_diu_mode_db), NULL, default_bpp);
   1517		if (rc)
   1518			has_default_mode = 1;
   1519	}
   1520
   1521	/* Still not found, use preferred mode from database if any */
   1522	if (!has_default_mode && info->monspecs.modedb) {
   1523		struct fb_monspecs *specs = &info->monspecs;
   1524		struct fb_videomode *modedb = &specs->modedb[0];
   1525
   1526		/*
   1527		 * Get preferred timing. If not found,
   1528		 * first mode in database will be used.
   1529		 */
   1530		if (specs->misc & FB_MISC_1ST_DETAIL) {
   1531			int i;
   1532
   1533			for (i = 0; i < specs->modedb_len; i++) {
   1534				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
   1535					modedb = &specs->modedb[i];
   1536					break;
   1537				}
   1538			}
   1539		}
   1540
   1541		info->var.bits_per_pixel = default_bpp;
   1542		fb_videomode_to_var(&info->var, modedb);
   1543	}
   1544
   1545	if (fsl_diu_check_var(&info->var, info)) {
   1546		dev_err(info->dev, "fsl_diu_check_var failed\n");
   1547		unmap_video_memory(info);
   1548		fb_dealloc_cmap(&info->cmap);
   1549		return -EINVAL;
   1550	}
   1551
   1552	if (register_framebuffer(info) < 0) {
   1553		dev_err(info->dev, "register_framebuffer failed\n");
   1554		unmap_video_memory(info);
   1555		fb_dealloc_cmap(&info->cmap);
   1556		return -EINVAL;
   1557	}
   1558
   1559	mfbi->registered = 1;
   1560	dev_info(info->dev, "%s registered successfully\n", mfbi->id);
   1561
   1562	return 0;
   1563}
   1564
   1565static void uninstall_fb(struct fb_info *info)
   1566{
   1567	struct mfb_info *mfbi = info->par;
   1568
   1569	if (!mfbi->registered)
   1570		return;
   1571
   1572	unregister_framebuffer(info);
   1573	unmap_video_memory(info);
   1574	fb_dealloc_cmap(&info->cmap);
   1575
   1576	mfbi->registered = 0;
   1577}
   1578
   1579static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
   1580{
   1581	struct diu __iomem *hw = dev_id;
   1582	uint32_t status = in_be32(&hw->int_status);
   1583
   1584	if (status) {
   1585		/* This is the workaround for underrun */
   1586		if (status & INT_UNDRUN) {
   1587			out_be32(&hw->diu_mode, 0);
   1588			udelay(1);
   1589			out_be32(&hw->diu_mode, 1);
   1590		}
   1591#if defined(CONFIG_NOT_COHERENT_CACHE)
   1592		else if (status & INT_VSYNC) {
   1593			unsigned int i;
   1594
   1595			for (i = 0; i < coherence_data_size;
   1596				i += d_cache_line_size)
   1597				__asm__ __volatile__ (
   1598					"dcbz 0, %[input]"
   1599				::[input]"r"(&coherence_data[i]));
   1600		}
   1601#endif
   1602		return IRQ_HANDLED;
   1603	}
   1604	return IRQ_NONE;
   1605}
   1606
   1607#ifdef CONFIG_PM
   1608/*
   1609 * Power management hooks. Note that we won't be called from IRQ context,
   1610 * unlike the blank functions above, so we may sleep.
   1611 */
   1612static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
   1613{
   1614	struct fsl_diu_data *data;
   1615
   1616	data = dev_get_drvdata(&ofdev->dev);
   1617	disable_lcdc(data->fsl_diu_info);
   1618
   1619	return 0;
   1620}
   1621
   1622static int fsl_diu_resume(struct platform_device *ofdev)
   1623{
   1624	struct fsl_diu_data *data;
   1625	unsigned int i;
   1626
   1627	data = dev_get_drvdata(&ofdev->dev);
   1628
   1629	fsl_diu_enable_interrupts(data);
   1630	update_lcdc(data->fsl_diu_info);
   1631	for (i = 0; i < NUM_AOIS; i++) {
   1632		if (data->mfb[i].count)
   1633			fsl_diu_enable_panel(&data->fsl_diu_info[i]);
   1634	}
   1635
   1636	return 0;
   1637}
   1638
   1639#else
   1640#define fsl_diu_suspend NULL
   1641#define fsl_diu_resume NULL
   1642#endif				/* CONFIG_PM */
   1643
   1644static ssize_t store_monitor(struct device *device,
   1645	struct device_attribute *attr, const char *buf, size_t count)
   1646{
   1647	enum fsl_diu_monitor_port old_monitor_port;
   1648	struct fsl_diu_data *data =
   1649		container_of(attr, struct fsl_diu_data, dev_attr);
   1650
   1651	old_monitor_port = data->monitor_port;
   1652	data->monitor_port = fsl_diu_name_to_port(buf);
   1653
   1654	if (old_monitor_port != data->monitor_port) {
   1655		/* All AOIs need adjust pixel format
   1656		 * fsl_diu_set_par only change the pixsel format here
   1657		 * unlikely to fail. */
   1658		unsigned int i;
   1659
   1660		for (i=0; i < NUM_AOIS; i++)
   1661			fsl_diu_set_par(&data->fsl_diu_info[i]);
   1662	}
   1663	return count;
   1664}
   1665
   1666static ssize_t show_monitor(struct device *device,
   1667	struct device_attribute *attr, char *buf)
   1668{
   1669	struct fsl_diu_data *data =
   1670		container_of(attr, struct fsl_diu_data, dev_attr);
   1671
   1672	switch (data->monitor_port) {
   1673	case FSL_DIU_PORT_DVI:
   1674		return sprintf(buf, "DVI\n");
   1675	case FSL_DIU_PORT_LVDS:
   1676		return sprintf(buf, "Single-link LVDS\n");
   1677	case FSL_DIU_PORT_DLVDS:
   1678		return sprintf(buf, "Dual-link LVDS\n");
   1679	}
   1680
   1681	return 0;
   1682}
   1683
   1684static int fsl_diu_probe(struct platform_device *pdev)
   1685{
   1686	struct device_node *np = pdev->dev.of_node;
   1687	struct mfb_info *mfbi;
   1688	struct fsl_diu_data *data;
   1689	dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */
   1690	const void *prop;
   1691	unsigned int i;
   1692	int ret;
   1693
   1694	data = dmam_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
   1695				   &dma_addr, GFP_DMA | __GFP_ZERO);
   1696	if (!data)
   1697		return -ENOMEM;
   1698	data->dma_addr = dma_addr;
   1699
   1700	/*
   1701	 * dma_alloc_coherent() uses a page allocator, so the address is
   1702	 * always page-aligned.  We need the memory to be 32-byte aligned,
   1703	 * so that's good.  However, if one day the allocator changes, we
   1704	 * need to catch that.  It's not worth the effort to handle unaligned
   1705	 * alloctions now because it's highly unlikely to ever be a problem.
   1706	 */
   1707	if ((unsigned long)data & 31) {
   1708		dev_err(&pdev->dev, "misaligned allocation");
   1709		ret = -ENOMEM;
   1710		goto error;
   1711	}
   1712
   1713	spin_lock_init(&data->reg_lock);
   1714
   1715	for (i = 0; i < NUM_AOIS; i++) {
   1716		struct fb_info *info = &data->fsl_diu_info[i];
   1717
   1718		info->device = &pdev->dev;
   1719		info->par = &data->mfb[i];
   1720
   1721		/*
   1722		 * We store the physical address of the AD in the reserved
   1723		 * 'paddr' field of the AD itself.
   1724		 */
   1725		data->ad[i].paddr = DMA_ADDR(data, ad[i]);
   1726
   1727		info->fix.smem_start = 0;
   1728
   1729		/* Initialize the AOI data structure */
   1730		mfbi = info->par;
   1731		memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
   1732		mfbi->parent = data;
   1733		mfbi->ad = &data->ad[i];
   1734	}
   1735
   1736	/* Get the EDID data from the device tree, if present */
   1737	prop = of_get_property(np, "edid", &ret);
   1738	if (prop && ret == EDID_LENGTH) {
   1739		memcpy(data->edid_data, prop, EDID_LENGTH);
   1740		data->has_edid = true;
   1741	}
   1742
   1743	data->diu_reg = of_iomap(np, 0);
   1744	if (!data->diu_reg) {
   1745		dev_err(&pdev->dev, "cannot map DIU registers\n");
   1746		ret = -EFAULT;
   1747		goto error;
   1748	}
   1749
   1750	/* Get the IRQ of the DIU */
   1751	data->irq = irq_of_parse_and_map(np, 0);
   1752
   1753	if (!data->irq) {
   1754		dev_err(&pdev->dev, "could not get DIU IRQ\n");
   1755		ret = -EINVAL;
   1756		goto error;
   1757	}
   1758	data->monitor_port = monitor_port;
   1759
   1760	/* Initialize the dummy Area Descriptor */
   1761	data->dummy_ad.addr = cpu_to_le32(DMA_ADDR(data, dummy_aoi));
   1762	data->dummy_ad.pix_fmt = 0x88882317;
   1763	data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
   1764	data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) |  2);
   1765	data->dummy_ad.offset_xyi = 0;
   1766	data->dummy_ad.offset_xyd = 0;
   1767	data->dummy_ad.next_ad = 0;
   1768	data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad);
   1769
   1770	/*
   1771	 * Let DIU continue to display splash screen if it was pre-initialized
   1772	 * by the bootloader; otherwise, clear the display.
   1773	 */
   1774	if (in_be32(&data->diu_reg->diu_mode) == MFB_MODE0)
   1775		out_be32(&data->diu_reg->desc[0], 0);
   1776
   1777	out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr);
   1778	out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr);
   1779
   1780	/*
   1781	 * Older versions of U-Boot leave interrupts enabled, so disable
   1782	 * all of them and clear the status register.
   1783	 */
   1784	out_be32(&data->diu_reg->int_mask, 0xffffffff);
   1785	in_be32(&data->diu_reg->int_status);
   1786
   1787	ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb",
   1788			  data->diu_reg);
   1789	if (ret) {
   1790		dev_err(&pdev->dev, "could not claim irq\n");
   1791		goto error;
   1792	}
   1793
   1794	for (i = 0; i < NUM_AOIS; i++) {
   1795		ret = install_fb(&data->fsl_diu_info[i]);
   1796		if (ret) {
   1797			dev_err(&pdev->dev, "could not register fb %d\n", i);
   1798			free_irq(data->irq, data->diu_reg);
   1799			goto error;
   1800		}
   1801	}
   1802
   1803	sysfs_attr_init(&data->dev_attr.attr);
   1804	data->dev_attr.attr.name = "monitor";
   1805	data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
   1806	data->dev_attr.show = show_monitor;
   1807	data->dev_attr.store = store_monitor;
   1808	ret = device_create_file(&pdev->dev, &data->dev_attr);
   1809	if (ret) {
   1810		dev_err(&pdev->dev, "could not create sysfs file %s\n",
   1811			data->dev_attr.attr.name);
   1812	}
   1813
   1814	dev_set_drvdata(&pdev->dev, data);
   1815	return 0;
   1816
   1817error:
   1818	for (i = 0; i < NUM_AOIS; i++)
   1819		uninstall_fb(&data->fsl_diu_info[i]);
   1820
   1821	iounmap(data->diu_reg);
   1822
   1823	return ret;
   1824}
   1825
   1826static int fsl_diu_remove(struct platform_device *pdev)
   1827{
   1828	struct fsl_diu_data *data;
   1829	int i;
   1830
   1831	data = dev_get_drvdata(&pdev->dev);
   1832	disable_lcdc(&data->fsl_diu_info[0]);
   1833
   1834	free_irq(data->irq, data->diu_reg);
   1835
   1836	for (i = 0; i < NUM_AOIS; i++)
   1837		uninstall_fb(&data->fsl_diu_info[i]);
   1838
   1839	iounmap(data->diu_reg);
   1840
   1841	return 0;
   1842}
   1843
   1844#ifndef MODULE
   1845static int __init fsl_diu_setup(char *options)
   1846{
   1847	char *opt;
   1848	unsigned long val;
   1849
   1850	if (!options || !*options)
   1851		return 0;
   1852
   1853	while ((opt = strsep(&options, ",")) != NULL) {
   1854		if (!*opt)
   1855			continue;
   1856		if (!strncmp(opt, "monitor=", 8)) {
   1857			monitor_port = fsl_diu_name_to_port(opt + 8);
   1858		} else if (!strncmp(opt, "bpp=", 4)) {
   1859			if (!kstrtoul(opt + 4, 10, &val))
   1860				default_bpp = val;
   1861		} else
   1862			fb_mode = opt;
   1863	}
   1864
   1865	return 0;
   1866}
   1867#endif
   1868
   1869static const struct of_device_id fsl_diu_match[] = {
   1870#ifdef CONFIG_PPC_MPC512x
   1871	{
   1872		.compatible = "fsl,mpc5121-diu",
   1873	},
   1874#endif
   1875	{
   1876		.compatible = "fsl,diu",
   1877	},
   1878	{}
   1879};
   1880MODULE_DEVICE_TABLE(of, fsl_diu_match);
   1881
   1882static struct platform_driver fsl_diu_driver = {
   1883	.driver = {
   1884		.name = "fsl-diu-fb",
   1885		.of_match_table = fsl_diu_match,
   1886	},
   1887	.probe  	= fsl_diu_probe,
   1888	.remove 	= fsl_diu_remove,
   1889	.suspend	= fsl_diu_suspend,
   1890	.resume		= fsl_diu_resume,
   1891};
   1892
   1893static int __init fsl_diu_init(void)
   1894{
   1895#ifdef CONFIG_NOT_COHERENT_CACHE
   1896	struct device_node *np;
   1897	const u32 *prop;
   1898#endif
   1899	int ret;
   1900#ifndef MODULE
   1901	char *option;
   1902
   1903	/*
   1904	 * For kernel boot options (in 'video=xxxfb:<options>' format)
   1905	 */
   1906	if (fb_get_options("fslfb", &option))
   1907		return -ENODEV;
   1908	fsl_diu_setup(option);
   1909#else
   1910	monitor_port = fsl_diu_name_to_port(monitor_string);
   1911#endif
   1912
   1913	/*
   1914	 * Must to verify set_pixel_clock. If not implement on platform,
   1915	 * then that means that there is no platform support for the DIU.
   1916	 */
   1917	if (!diu_ops.set_pixel_clock)
   1918		return -ENODEV;
   1919
   1920	pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
   1921
   1922#ifdef CONFIG_NOT_COHERENT_CACHE
   1923	np = of_get_cpu_node(0, NULL);
   1924	if (!np) {
   1925		pr_err("fsl-diu-fb: can't find 'cpu' device node\n");
   1926		return -ENODEV;
   1927	}
   1928
   1929	prop = of_get_property(np, "d-cache-size", NULL);
   1930	if (prop == NULL) {
   1931		pr_err("fsl-diu-fb: missing 'd-cache-size' property' "
   1932		       "in 'cpu' node\n");
   1933		of_node_put(np);
   1934		return -ENODEV;
   1935	}
   1936
   1937	/*
   1938	 * Freescale PLRU requires 13/8 times the cache size to do a proper
   1939	 * displacement flush
   1940	 */
   1941	coherence_data_size = be32_to_cpup(prop) * 13;
   1942	coherence_data_size /= 8;
   1943
   1944	pr_debug("fsl-diu-fb: coherence data size is %zu bytes\n",
   1945		 coherence_data_size);
   1946
   1947	prop = of_get_property(np, "d-cache-line-size", NULL);
   1948	if (prop == NULL) {
   1949		pr_err("fsl-diu-fb: missing 'd-cache-line-size' property' "
   1950		       "in 'cpu' node\n");
   1951		of_node_put(np);
   1952		return -ENODEV;
   1953	}
   1954	d_cache_line_size = be32_to_cpup(prop);
   1955
   1956	pr_debug("fsl-diu-fb: cache lines size is %u bytes\n",
   1957		 d_cache_line_size);
   1958
   1959	of_node_put(np);
   1960	coherence_data = vmalloc(coherence_data_size);
   1961	if (!coherence_data)
   1962		return -ENOMEM;
   1963#endif
   1964
   1965	ret = platform_driver_register(&fsl_diu_driver);
   1966	if (ret) {
   1967		pr_err("fsl-diu-fb: failed to register platform driver\n");
   1968#if defined(CONFIG_NOT_COHERENT_CACHE)
   1969		vfree(coherence_data);
   1970#endif
   1971	}
   1972	return ret;
   1973}
   1974
   1975static void __exit fsl_diu_exit(void)
   1976{
   1977	platform_driver_unregister(&fsl_diu_driver);
   1978#if defined(CONFIG_NOT_COHERENT_CACHE)
   1979	vfree(coherence_data);
   1980#endif
   1981}
   1982
   1983module_init(fsl_diu_init);
   1984module_exit(fsl_diu_exit);
   1985
   1986MODULE_AUTHOR("York Sun <yorksun@freescale.com>");
   1987MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
   1988MODULE_LICENSE("GPL");
   1989
   1990module_param_named(mode, fb_mode, charp, 0);
   1991MODULE_PARM_DESC(mode,
   1992	"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
   1993module_param_named(bpp, default_bpp, ulong, 0);
   1994MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified in 'mode'");
   1995module_param_named(monitor, monitor_string, charp, 0);
   1996MODULE_PARM_DESC(monitor, "Specify the monitor port "
   1997	"(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");
   1998