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

omapfb-main.c (59576B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * linux/drivers/video/omap2/omapfb-main.c
      4 *
      5 * Copyright (C) 2008 Nokia Corporation
      6 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
      7 *
      8 * Some code and ideas taken from drivers/video/omap/ driver
      9 * by Imre Deak.
     10 */
     11
     12#include <linux/module.h>
     13#include <linux/delay.h>
     14#include <linux/slab.h>
     15#include <linux/fb.h>
     16#include <linux/dma-mapping.h>
     17#include <linux/vmalloc.h>
     18#include <linux/device.h>
     19#include <linux/platform_device.h>
     20#include <linux/omapfb.h>
     21
     22#include <video/omapfb_dss.h>
     23#include <video/omapvrfb.h>
     24
     25#include "omapfb.h"
     26
     27#define MODULE_NAME     "omapfb"
     28
     29#define OMAPFB_PLANE_XRES_MIN		8
     30#define OMAPFB_PLANE_YRES_MIN		8
     31
     32static char *def_mode;
     33static char *def_vram;
     34static bool def_vrfb;
     35static int def_rotate;
     36static bool def_mirror;
     37static bool auto_update;
     38static unsigned int auto_update_freq;
     39module_param(auto_update, bool, 0);
     40module_param(auto_update_freq, uint, 0644);
     41
     42#ifdef DEBUG
     43bool omapfb_debug;
     44module_param_named(debug, omapfb_debug, bool, 0644);
     45static bool omapfb_test_pattern;
     46module_param_named(test, omapfb_test_pattern, bool, 0644);
     47#endif
     48
     49static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
     50static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
     51		struct omap_dss_device *dssdev);
     52
     53#ifdef DEBUG
     54static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
     55{
     56	struct fb_var_screeninfo *var = &fbi->var;
     57	struct fb_fix_screeninfo *fix = &fbi->fix;
     58	void __iomem *addr = fbi->screen_base;
     59	const unsigned bytespp = var->bits_per_pixel >> 3;
     60	const unsigned line_len = fix->line_length / bytespp;
     61
     62	int r = (color >> 16) & 0xff;
     63	int g = (color >> 8) & 0xff;
     64	int b = (color >> 0) & 0xff;
     65
     66	if (var->bits_per_pixel == 16) {
     67		u16 __iomem *p = (u16 __iomem *)addr;
     68		p += y * line_len + x;
     69
     70		r = r * 32 / 256;
     71		g = g * 64 / 256;
     72		b = b * 32 / 256;
     73
     74		__raw_writew((r << 11) | (g << 5) | (b << 0), p);
     75	} else if (var->bits_per_pixel == 24) {
     76		u8 __iomem *p = (u8 __iomem *)addr;
     77		p += (y * line_len + x) * 3;
     78
     79		__raw_writeb(b, p + 0);
     80		__raw_writeb(g, p + 1);
     81		__raw_writeb(r, p + 2);
     82	} else if (var->bits_per_pixel == 32) {
     83		u32 __iomem *p = (u32 __iomem *)addr;
     84		p += y * line_len + x;
     85		__raw_writel(color, p);
     86	}
     87}
     88
     89static void fill_fb(struct fb_info *fbi)
     90{
     91	struct fb_var_screeninfo *var = &fbi->var;
     92	const short w = var->xres_virtual;
     93	const short h = var->yres_virtual;
     94	void __iomem *addr = fbi->screen_base;
     95	int y, x;
     96
     97	if (!addr)
     98		return;
     99
    100	DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
    101
    102	for (y = 0; y < h; y++) {
    103		for (x = 0; x < w; x++) {
    104			if (x < 20 && y < 20)
    105				draw_pixel(fbi, x, y, 0xffffff);
    106			else if (x < 20 && (y > 20 && y < h - 20))
    107				draw_pixel(fbi, x, y, 0xff);
    108			else if (y < 20 && (x > 20 && x < w - 20))
    109				draw_pixel(fbi, x, y, 0xff00);
    110			else if (x > w - 20 && (y > 20 && y < h - 20))
    111				draw_pixel(fbi, x, y, 0xff0000);
    112			else if (y > h - 20 && (x > 20 && x < w - 20))
    113				draw_pixel(fbi, x, y, 0xffff00);
    114			else if (x == 20 || x == w - 20 ||
    115					y == 20 || y == h - 20)
    116				draw_pixel(fbi, x, y, 0xffffff);
    117			else if (x == y || w - x == h - y)
    118				draw_pixel(fbi, x, y, 0xff00ff);
    119			else if (w - x == y || x == h - y)
    120				draw_pixel(fbi, x, y, 0x00ffff);
    121			else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
    122				int t = x * 3 / w;
    123				unsigned r = 0, g = 0, b = 0;
    124				unsigned c;
    125				if (var->bits_per_pixel == 16) {
    126					if (t == 0)
    127						b = (y % 32) * 256 / 32;
    128					else if (t == 1)
    129						g = (y % 64) * 256 / 64;
    130					else if (t == 2)
    131						r = (y % 32) * 256 / 32;
    132				} else {
    133					if (t == 0)
    134						b = (y % 256);
    135					else if (t == 1)
    136						g = (y % 256);
    137					else if (t == 2)
    138						r = (y % 256);
    139				}
    140				c = (r << 16) | (g << 8) | (b << 0);
    141				draw_pixel(fbi, x, y, c);
    142			} else {
    143				draw_pixel(fbi, x, y, 0);
    144			}
    145		}
    146	}
    147}
    148#endif
    149
    150static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
    151{
    152	const struct vrfb *vrfb = &ofbi->region->vrfb;
    153	unsigned offset;
    154
    155	switch (rot) {
    156	case FB_ROTATE_UR:
    157		offset = 0;
    158		break;
    159	case FB_ROTATE_CW:
    160		offset = vrfb->yoffset;
    161		break;
    162	case FB_ROTATE_UD:
    163		offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
    164		break;
    165	case FB_ROTATE_CCW:
    166		offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
    167		break;
    168	default:
    169		BUG();
    170		return 0;
    171	}
    172
    173	offset *= vrfb->bytespp;
    174
    175	return offset;
    176}
    177
    178static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
    179{
    180	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
    181		return ofbi->region->vrfb.paddr[rot]
    182			+ omapfb_get_vrfb_offset(ofbi, rot);
    183	} else {
    184		return ofbi->region->paddr;
    185	}
    186}
    187
    188static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
    189{
    190	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
    191		return ofbi->region->vrfb.paddr[0];
    192	else
    193		return ofbi->region->paddr;
    194}
    195
    196static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
    197{
    198	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
    199		return ofbi->region->vrfb.vaddr[0];
    200	else
    201		return ofbi->region->vaddr;
    202}
    203
    204static struct omapfb_colormode omapfb_colormodes[] = {
    205	{
    206		.dssmode = OMAP_DSS_COLOR_UYVY,
    207		.bits_per_pixel = 16,
    208		.nonstd = OMAPFB_COLOR_YUV422,
    209	}, {
    210		.dssmode = OMAP_DSS_COLOR_YUV2,
    211		.bits_per_pixel = 16,
    212		.nonstd = OMAPFB_COLOR_YUY422,
    213	}, {
    214		.dssmode = OMAP_DSS_COLOR_ARGB16,
    215		.bits_per_pixel = 16,
    216		.red	= { .length = 4, .offset = 8, .msb_right = 0 },
    217		.green	= { .length = 4, .offset = 4, .msb_right = 0 },
    218		.blue	= { .length = 4, .offset = 0, .msb_right = 0 },
    219		.transp	= { .length = 4, .offset = 12, .msb_right = 0 },
    220	}, {
    221		.dssmode = OMAP_DSS_COLOR_RGB16,
    222		.bits_per_pixel = 16,
    223		.red	= { .length = 5, .offset = 11, .msb_right = 0 },
    224		.green	= { .length = 6, .offset = 5, .msb_right = 0 },
    225		.blue	= { .length = 5, .offset = 0, .msb_right = 0 },
    226		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
    227	}, {
    228		.dssmode = OMAP_DSS_COLOR_RGB24P,
    229		.bits_per_pixel = 24,
    230		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
    231		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
    232		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
    233		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
    234	}, {
    235		.dssmode = OMAP_DSS_COLOR_RGB24U,
    236		.bits_per_pixel = 32,
    237		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
    238		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
    239		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
    240		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
    241	}, {
    242		.dssmode = OMAP_DSS_COLOR_ARGB32,
    243		.bits_per_pixel = 32,
    244		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
    245		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
    246		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
    247		.transp	= { .length = 8, .offset = 24, .msb_right = 0 },
    248	}, {
    249		.dssmode = OMAP_DSS_COLOR_RGBA32,
    250		.bits_per_pixel = 32,
    251		.red	= { .length = 8, .offset = 24, .msb_right = 0 },
    252		.green	= { .length = 8, .offset = 16, .msb_right = 0 },
    253		.blue	= { .length = 8, .offset = 8, .msb_right = 0 },
    254		.transp	= { .length = 8, .offset = 0, .msb_right = 0 },
    255	}, {
    256		.dssmode = OMAP_DSS_COLOR_RGBX32,
    257		.bits_per_pixel = 32,
    258		.red	= { .length = 8, .offset = 24, .msb_right = 0 },
    259		.green	= { .length = 8, .offset = 16, .msb_right = 0 },
    260		.blue	= { .length = 8, .offset = 8, .msb_right = 0 },
    261		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
    262	},
    263};
    264
    265static bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
    266{
    267	return f1->length == f2->length &&
    268		f1->offset == f2->offset &&
    269		f1->msb_right == f2->msb_right;
    270}
    271
    272static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
    273		struct omapfb_colormode *color)
    274{
    275	if (var->bits_per_pixel == 0 ||
    276			var->red.length == 0 ||
    277			var->blue.length == 0 ||
    278			var->green.length == 0)
    279		return false;
    280
    281	return var->bits_per_pixel == color->bits_per_pixel &&
    282		cmp_component(&var->red, &color->red) &&
    283		cmp_component(&var->green, &color->green) &&
    284		cmp_component(&var->blue, &color->blue) &&
    285		cmp_component(&var->transp, &color->transp);
    286}
    287
    288static void assign_colormode_to_var(struct fb_var_screeninfo *var,
    289		struct omapfb_colormode *color)
    290{
    291	var->bits_per_pixel = color->bits_per_pixel;
    292	var->nonstd = color->nonstd;
    293	var->red = color->red;
    294	var->green = color->green;
    295	var->blue = color->blue;
    296	var->transp = color->transp;
    297}
    298
    299static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
    300		enum omap_color_mode *mode)
    301{
    302	enum omap_color_mode dssmode;
    303	int i;
    304
    305	/* first match with nonstd field */
    306	if (var->nonstd) {
    307		for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
    308			struct omapfb_colormode *m = &omapfb_colormodes[i];
    309			if (var->nonstd == m->nonstd) {
    310				assign_colormode_to_var(var, m);
    311				*mode = m->dssmode;
    312				return 0;
    313			}
    314		}
    315
    316		return -EINVAL;
    317	}
    318
    319	/* then try exact match of bpp and colors */
    320	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
    321		struct omapfb_colormode *m = &omapfb_colormodes[i];
    322		if (cmp_var_to_colormode(var, m)) {
    323			assign_colormode_to_var(var, m);
    324			*mode = m->dssmode;
    325			return 0;
    326		}
    327	}
    328
    329	/* match with bpp if user has not filled color fields
    330	 * properly */
    331	switch (var->bits_per_pixel) {
    332	case 1:
    333		dssmode = OMAP_DSS_COLOR_CLUT1;
    334		break;
    335	case 2:
    336		dssmode = OMAP_DSS_COLOR_CLUT2;
    337		break;
    338	case 4:
    339		dssmode = OMAP_DSS_COLOR_CLUT4;
    340		break;
    341	case 8:
    342		dssmode = OMAP_DSS_COLOR_CLUT8;
    343		break;
    344	case 12:
    345		dssmode = OMAP_DSS_COLOR_RGB12U;
    346		break;
    347	case 16:
    348		dssmode = OMAP_DSS_COLOR_RGB16;
    349		break;
    350	case 24:
    351		dssmode = OMAP_DSS_COLOR_RGB24P;
    352		break;
    353	case 32:
    354		dssmode = OMAP_DSS_COLOR_RGB24U;
    355		break;
    356	default:
    357		return -EINVAL;
    358	}
    359
    360	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
    361		struct omapfb_colormode *m = &omapfb_colormodes[i];
    362		if (dssmode == m->dssmode) {
    363			assign_colormode_to_var(var, m);
    364			*mode = m->dssmode;
    365			return 0;
    366		}
    367	}
    368
    369	return -EINVAL;
    370}
    371
    372static int check_fb_res_bounds(struct fb_var_screeninfo *var)
    373{
    374	int xres_min = OMAPFB_PLANE_XRES_MIN;
    375	int xres_max = 2048;
    376	int yres_min = OMAPFB_PLANE_YRES_MIN;
    377	int yres_max = 2048;
    378
    379	/* XXX: some applications seem to set virtual res to 0. */
    380	if (var->xres_virtual == 0)
    381		var->xres_virtual = var->xres;
    382
    383	if (var->yres_virtual == 0)
    384		var->yres_virtual = var->yres;
    385
    386	if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
    387		return -EINVAL;
    388
    389	if (var->xres < xres_min)
    390		var->xres = xres_min;
    391	if (var->yres < yres_min)
    392		var->yres = yres_min;
    393	if (var->xres > xres_max)
    394		var->xres = xres_max;
    395	if (var->yres > yres_max)
    396		var->yres = yres_max;
    397
    398	if (var->xres > var->xres_virtual)
    399		var->xres = var->xres_virtual;
    400	if (var->yres > var->yres_virtual)
    401		var->yres = var->yres_virtual;
    402
    403	return 0;
    404}
    405
    406static void shrink_height(unsigned long max_frame_size,
    407		struct fb_var_screeninfo *var)
    408{
    409	DBG("can't fit FB into memory, reducing y\n");
    410	var->yres_virtual = max_frame_size /
    411		(var->xres_virtual * var->bits_per_pixel >> 3);
    412
    413	if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
    414		var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
    415
    416	if (var->yres > var->yres_virtual)
    417		var->yres = var->yres_virtual;
    418}
    419
    420static void shrink_width(unsigned long max_frame_size,
    421		struct fb_var_screeninfo *var)
    422{
    423	DBG("can't fit FB into memory, reducing x\n");
    424	var->xres_virtual = max_frame_size / var->yres_virtual /
    425		(var->bits_per_pixel >> 3);
    426
    427	if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
    428		var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
    429
    430	if (var->xres > var->xres_virtual)
    431		var->xres = var->xres_virtual;
    432}
    433
    434static int check_vrfb_fb_size(unsigned long region_size,
    435		const struct fb_var_screeninfo *var)
    436{
    437	unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
    438		var->yres_virtual, var->bits_per_pixel >> 3);
    439
    440	return min_phys_size > region_size ? -EINVAL : 0;
    441}
    442
    443static int check_fb_size(const struct omapfb_info *ofbi,
    444		struct fb_var_screeninfo *var)
    445{
    446	unsigned long max_frame_size = ofbi->region->size;
    447	int bytespp = var->bits_per_pixel >> 3;
    448	unsigned long line_size = var->xres_virtual * bytespp;
    449
    450	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
    451		/* One needs to check for both VRFB and OMAPFB limitations. */
    452		if (check_vrfb_fb_size(max_frame_size, var))
    453			shrink_height(omap_vrfb_max_height(
    454				max_frame_size, var->xres_virtual, bytespp) *
    455				line_size, var);
    456
    457		if (check_vrfb_fb_size(max_frame_size, var)) {
    458			DBG("cannot fit FB to memory\n");
    459			return -EINVAL;
    460		}
    461
    462		return 0;
    463	}
    464
    465	DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
    466
    467	if (line_size * var->yres_virtual > max_frame_size)
    468		shrink_height(max_frame_size, var);
    469
    470	if (line_size * var->yres_virtual > max_frame_size) {
    471		shrink_width(max_frame_size, var);
    472		line_size = var->xres_virtual * bytespp;
    473	}
    474
    475	if (line_size * var->yres_virtual > max_frame_size) {
    476		DBG("cannot fit FB to memory\n");
    477		return -EINVAL;
    478	}
    479
    480	return 0;
    481}
    482
    483/*
    484 * Consider if VRFB assisted rotation is in use and if the virtual space for
    485 * the zero degree view needs to be mapped. The need for mapping also acts as
    486 * the trigger for setting up the hardware on the context in question. This
    487 * ensures that one does not attempt to access the virtual view before the
    488 * hardware is serving the address translations.
    489 */
    490static int setup_vrfb_rotation(struct fb_info *fbi)
    491{
    492	struct omapfb_info *ofbi = FB2OFB(fbi);
    493	struct omapfb2_mem_region *rg = ofbi->region;
    494	struct vrfb *vrfb = &rg->vrfb;
    495	struct fb_var_screeninfo *var = &fbi->var;
    496	struct fb_fix_screeninfo *fix = &fbi->fix;
    497	unsigned bytespp;
    498	bool yuv_mode;
    499	enum omap_color_mode mode;
    500	int r;
    501	bool reconf;
    502
    503	if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
    504		return 0;
    505
    506	DBG("setup_vrfb_rotation\n");
    507
    508	r = fb_mode_to_dss_mode(var, &mode);
    509	if (r)
    510		return r;
    511
    512	bytespp = var->bits_per_pixel >> 3;
    513
    514	yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
    515
    516	/* We need to reconfigure VRFB if the resolution changes, if yuv mode
    517	 * is enabled/disabled, or if bytes per pixel changes */
    518
    519	/* XXX we shouldn't allow this when framebuffer is mmapped */
    520
    521	reconf = false;
    522
    523	if (yuv_mode != vrfb->yuv_mode)
    524		reconf = true;
    525	else if (bytespp != vrfb->bytespp)
    526		reconf = true;
    527	else if (vrfb->xres != var->xres_virtual ||
    528			vrfb->yres != var->yres_virtual)
    529		reconf = true;
    530
    531	if (vrfb->vaddr[0] && reconf) {
    532		fbi->screen_base = NULL;
    533		fix->smem_start = 0;
    534		fix->smem_len = 0;
    535		iounmap(vrfb->vaddr[0]);
    536		vrfb->vaddr[0] = NULL;
    537		DBG("setup_vrfb_rotation: reset fb\n");
    538	}
    539
    540	if (vrfb->vaddr[0])
    541		return 0;
    542
    543	omap_vrfb_setup(&rg->vrfb, rg->paddr,
    544			var->xres_virtual,
    545			var->yres_virtual,
    546			bytespp, yuv_mode);
    547
    548	/* Now one can ioremap the 0 angle view */
    549	r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
    550	if (r)
    551		return r;
    552
    553	/* used by open/write in fbmem.c */
    554	fbi->screen_base = ofbi->region->vrfb.vaddr[0];
    555
    556	fix->smem_start = ofbi->region->vrfb.paddr[0];
    557
    558	switch (var->nonstd) {
    559	case OMAPFB_COLOR_YUV422:
    560	case OMAPFB_COLOR_YUY422:
    561		fix->line_length =
    562			(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
    563		break;
    564	default:
    565		fix->line_length =
    566			(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
    567		break;
    568	}
    569
    570	fix->smem_len = var->yres_virtual * fix->line_length;
    571
    572	return 0;
    573}
    574
    575int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
    576			struct fb_var_screeninfo *var)
    577{
    578	int i;
    579
    580	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
    581		struct omapfb_colormode *mode = &omapfb_colormodes[i];
    582		if (dssmode == mode->dssmode) {
    583			assign_colormode_to_var(var, mode);
    584			return 0;
    585		}
    586	}
    587	return -ENOENT;
    588}
    589
    590void set_fb_fix(struct fb_info *fbi)
    591{
    592	struct fb_fix_screeninfo *fix = &fbi->fix;
    593	struct fb_var_screeninfo *var = &fbi->var;
    594	struct omapfb_info *ofbi = FB2OFB(fbi);
    595	struct omapfb2_mem_region *rg = ofbi->region;
    596
    597	DBG("set_fb_fix\n");
    598
    599	/* used by open/write in fbmem.c */
    600	fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
    601
    602	/* used by mmap in fbmem.c */
    603	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
    604		switch (var->nonstd) {
    605		case OMAPFB_COLOR_YUV422:
    606		case OMAPFB_COLOR_YUY422:
    607			fix->line_length =
    608				(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
    609			break;
    610		default:
    611			fix->line_length =
    612				(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
    613			break;
    614		}
    615
    616		fix->smem_len = var->yres_virtual * fix->line_length;
    617	} else {
    618		fix->line_length =
    619			(var->xres_virtual * var->bits_per_pixel) >> 3;
    620		fix->smem_len = rg->size;
    621	}
    622
    623	fix->smem_start = omapfb_get_region_paddr(ofbi);
    624
    625	fix->type = FB_TYPE_PACKED_PIXELS;
    626
    627	if (var->nonstd)
    628		fix->visual = FB_VISUAL_PSEUDOCOLOR;
    629	else {
    630		switch (var->bits_per_pixel) {
    631		case 32:
    632		case 24:
    633		case 16:
    634		case 12:
    635			fix->visual = FB_VISUAL_TRUECOLOR;
    636			/* 12bpp is stored in 16 bits */
    637			break;
    638		case 1:
    639		case 2:
    640		case 4:
    641		case 8:
    642			fix->visual = FB_VISUAL_PSEUDOCOLOR;
    643			break;
    644		}
    645	}
    646
    647	fix->accel = FB_ACCEL_NONE;
    648
    649	fix->xpanstep = 1;
    650	fix->ypanstep = 1;
    651}
    652
    653/* check new var and possibly modify it to be ok */
    654int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
    655{
    656	struct omapfb_info *ofbi = FB2OFB(fbi);
    657	struct omap_dss_device *display = fb2display(fbi);
    658	enum omap_color_mode mode = 0;
    659	int i;
    660	int r;
    661
    662	DBG("check_fb_var %d\n", ofbi->id);
    663
    664	WARN_ON(!atomic_read(&ofbi->region->lock_count));
    665
    666	r = fb_mode_to_dss_mode(var, &mode);
    667	if (r) {
    668		DBG("cannot convert var to omap dss mode\n");
    669		return r;
    670	}
    671
    672	for (i = 0; i < ofbi->num_overlays; ++i) {
    673		if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
    674			DBG("invalid mode\n");
    675			return -EINVAL;
    676		}
    677	}
    678
    679	if (var->rotate > 3)
    680		return -EINVAL;
    681
    682	if (check_fb_res_bounds(var))
    683		return -EINVAL;
    684
    685	/* When no memory is allocated ignore the size check */
    686	if (ofbi->region->size != 0 && check_fb_size(ofbi, var))
    687		return -EINVAL;
    688
    689	if (var->xres + var->xoffset > var->xres_virtual)
    690		var->xoffset = var->xres_virtual - var->xres;
    691	if (var->yres + var->yoffset > var->yres_virtual)
    692		var->yoffset = var->yres_virtual - var->yres;
    693
    694	DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
    695			var->xres, var->yres,
    696			var->xres_virtual, var->yres_virtual);
    697
    698	if (display && display->driver->get_dimensions) {
    699		u32 w, h;
    700		display->driver->get_dimensions(display, &w, &h);
    701		var->width = DIV_ROUND_CLOSEST(w, 1000);
    702		var->height = DIV_ROUND_CLOSEST(h, 1000);
    703	} else {
    704		var->height = -1;
    705		var->width = -1;
    706	}
    707
    708	var->grayscale          = 0;
    709
    710	if (display && display->driver->get_timings) {
    711		struct omap_video_timings timings;
    712		display->driver->get_timings(display, &timings);
    713
    714		/* pixclock in ps, the rest in pixclock */
    715		var->pixclock = timings.pixelclock != 0 ?
    716			KHZ2PICOS(timings.pixelclock / 1000) :
    717			0;
    718		var->left_margin = timings.hbp;
    719		var->right_margin = timings.hfp;
    720		var->upper_margin = timings.vbp;
    721		var->lower_margin = timings.vfp;
    722		var->hsync_len = timings.hsw;
    723		var->vsync_len = timings.vsw;
    724		var->sync |= timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH ?
    725				FB_SYNC_HOR_HIGH_ACT : 0;
    726		var->sync |= timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH ?
    727				FB_SYNC_VERT_HIGH_ACT : 0;
    728		var->vmode = timings.interlace ?
    729				FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
    730	} else {
    731		var->pixclock = 0;
    732		var->left_margin = 0;
    733		var->right_margin = 0;
    734		var->upper_margin = 0;
    735		var->lower_margin = 0;
    736		var->hsync_len = 0;
    737		var->vsync_len = 0;
    738		var->sync = 0;
    739		var->vmode = FB_VMODE_NONINTERLACED;
    740	}
    741
    742	return 0;
    743}
    744
    745/*
    746 * ---------------------------------------------------------------------------
    747 * fbdev framework callbacks
    748 * ---------------------------------------------------------------------------
    749 */
    750static int omapfb_open(struct fb_info *fbi, int user)
    751{
    752	return 0;
    753}
    754
    755static int omapfb_release(struct fb_info *fbi, int user)
    756{
    757	return 0;
    758}
    759
    760static unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var,
    761		const struct fb_fix_screeninfo *fix, int rotation)
    762{
    763	unsigned offset;
    764
    765	offset = var->yoffset * fix->line_length +
    766		var->xoffset * (var->bits_per_pixel >> 3);
    767
    768	return offset;
    769}
    770
    771static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
    772		const struct fb_fix_screeninfo *fix, int rotation)
    773{
    774	unsigned offset;
    775
    776	if (rotation == FB_ROTATE_UD)
    777		offset = (var->yres_virtual - var->yres) *
    778			fix->line_length;
    779	else if (rotation == FB_ROTATE_CW)
    780		offset = (var->yres_virtual - var->yres) *
    781			(var->bits_per_pixel >> 3);
    782	else
    783		offset = 0;
    784
    785	if (rotation == FB_ROTATE_UR)
    786		offset += var->yoffset * fix->line_length +
    787			var->xoffset * (var->bits_per_pixel >> 3);
    788	else if (rotation == FB_ROTATE_UD)
    789		offset -= var->yoffset * fix->line_length +
    790			var->xoffset * (var->bits_per_pixel >> 3);
    791	else if (rotation == FB_ROTATE_CW)
    792		offset -= var->xoffset * fix->line_length +
    793			var->yoffset * (var->bits_per_pixel >> 3);
    794	else if (rotation == FB_ROTATE_CCW)
    795		offset += var->xoffset * fix->line_length +
    796			var->yoffset * (var->bits_per_pixel >> 3);
    797
    798	return offset;
    799}
    800
    801static void omapfb_calc_addr(const struct omapfb_info *ofbi,
    802			     const struct fb_var_screeninfo *var,
    803			     const struct fb_fix_screeninfo *fix,
    804			     int rotation, u32 *paddr)
    805{
    806	u32 data_start_p;
    807	int offset;
    808
    809	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
    810		data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
    811	else
    812		data_start_p = omapfb_get_region_paddr(ofbi);
    813
    814	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
    815		offset = calc_rotation_offset_vrfb(var, fix, rotation);
    816	else
    817		offset = calc_rotation_offset_dma(var, fix, rotation);
    818
    819	data_start_p += offset;
    820
    821	if (offset)
    822		DBG("offset %d, %d = %d\n",
    823		    var->xoffset, var->yoffset, offset);
    824
    825	DBG("paddr %x\n", data_start_p);
    826
    827	*paddr = data_start_p;
    828}
    829
    830/* setup overlay according to the fb */
    831int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
    832		u16 posx, u16 posy, u16 outw, u16 outh)
    833{
    834	int r = 0;
    835	struct omapfb_info *ofbi = FB2OFB(fbi);
    836	struct fb_var_screeninfo *var = &fbi->var;
    837	struct fb_fix_screeninfo *fix = &fbi->fix;
    838	enum omap_color_mode mode = 0;
    839	u32 data_start_p = 0;
    840	struct omap_overlay_info info;
    841	int xres, yres;
    842	int screen_width;
    843	int mirror;
    844	int rotation = var->rotate;
    845	int i;
    846
    847	WARN_ON(!atomic_read(&ofbi->region->lock_count));
    848
    849	for (i = 0; i < ofbi->num_overlays; i++) {
    850		if (ovl != ofbi->overlays[i])
    851			continue;
    852
    853		rotation = (rotation + ofbi->rotation[i]) % 4;
    854		break;
    855	}
    856
    857	DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
    858			posx, posy, outw, outh);
    859
    860	if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
    861		xres = var->yres;
    862		yres = var->xres;
    863	} else {
    864		xres = var->xres;
    865		yres = var->yres;
    866	}
    867
    868	if (ofbi->region->size)
    869		omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p);
    870
    871	r = fb_mode_to_dss_mode(var, &mode);
    872	if (r) {
    873		DBG("fb_mode_to_dss_mode failed");
    874		goto err;
    875	}
    876
    877	switch (var->nonstd) {
    878	case OMAPFB_COLOR_YUV422:
    879	case OMAPFB_COLOR_YUY422:
    880		if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
    881			screen_width = fix->line_length
    882				/ (var->bits_per_pixel >> 2);
    883			break;
    884		}
    885		fallthrough;
    886	default:
    887		screen_width = fix->line_length / (var->bits_per_pixel >> 3);
    888		break;
    889	}
    890
    891	ovl->get_overlay_info(ovl, &info);
    892
    893	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
    894		mirror = 0;
    895	else
    896		mirror = ofbi->mirror;
    897
    898	info.paddr = data_start_p;
    899	info.screen_width = screen_width;
    900	info.width = xres;
    901	info.height = yres;
    902	info.color_mode = mode;
    903	info.rotation_type = ofbi->rotation_type;
    904	info.rotation = rotation;
    905	info.mirror = mirror;
    906
    907	info.pos_x = posx;
    908	info.pos_y = posy;
    909	info.out_width = outw;
    910	info.out_height = outh;
    911
    912	r = ovl->set_overlay_info(ovl, &info);
    913	if (r) {
    914		DBG("ovl->setup_overlay_info failed\n");
    915		goto err;
    916	}
    917
    918	return 0;
    919
    920err:
    921	DBG("setup_overlay failed\n");
    922	return r;
    923}
    924
    925/* apply var to the overlay */
    926int omapfb_apply_changes(struct fb_info *fbi, int init)
    927{
    928	int r = 0;
    929	struct omapfb_info *ofbi = FB2OFB(fbi);
    930	struct fb_var_screeninfo *var = &fbi->var;
    931	struct omap_overlay *ovl;
    932	u16 posx, posy;
    933	u16 outw, outh;
    934	int i;
    935
    936#ifdef DEBUG
    937	if (omapfb_test_pattern)
    938		fill_fb(fbi);
    939#endif
    940
    941	WARN_ON(!atomic_read(&ofbi->region->lock_count));
    942
    943	for (i = 0; i < ofbi->num_overlays; i++) {
    944		ovl = ofbi->overlays[i];
    945
    946		DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
    947
    948		if (ofbi->region->size == 0) {
    949			/* the fb is not available. disable the overlay */
    950			omapfb_overlay_enable(ovl, 0);
    951			if (!init && ovl->manager)
    952				ovl->manager->apply(ovl->manager);
    953			continue;
    954		}
    955
    956		if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
    957			int rotation = (var->rotate + ofbi->rotation[i]) % 4;
    958			if (rotation == FB_ROTATE_CW ||
    959					rotation == FB_ROTATE_CCW) {
    960				outw = var->yres;
    961				outh = var->xres;
    962			} else {
    963				outw = var->xres;
    964				outh = var->yres;
    965			}
    966		} else {
    967			struct omap_overlay_info info;
    968			ovl->get_overlay_info(ovl, &info);
    969			outw = info.out_width;
    970			outh = info.out_height;
    971		}
    972
    973		if (init) {
    974			posx = 0;
    975			posy = 0;
    976		} else {
    977			struct omap_overlay_info info;
    978			ovl->get_overlay_info(ovl, &info);
    979			posx = info.pos_x;
    980			posy = info.pos_y;
    981		}
    982
    983		r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
    984		if (r)
    985			goto err;
    986
    987		if (!init && ovl->manager)
    988			ovl->manager->apply(ovl->manager);
    989	}
    990	return 0;
    991err:
    992	DBG("apply_changes failed\n");
    993	return r;
    994}
    995
    996/* checks var and eventually tweaks it to something supported,
    997 * DO NOT MODIFY PAR */
    998static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
    999{
   1000	struct omapfb_info *ofbi = FB2OFB(fbi);
   1001	int r;
   1002
   1003	DBG("check_var(%d)\n", FB2OFB(fbi)->id);
   1004
   1005	omapfb_get_mem_region(ofbi->region);
   1006
   1007	r = check_fb_var(fbi, var);
   1008
   1009	omapfb_put_mem_region(ofbi->region);
   1010
   1011	return r;
   1012}
   1013
   1014/* set the video mode according to info->var */
   1015static int omapfb_set_par(struct fb_info *fbi)
   1016{
   1017	struct omapfb_info *ofbi = FB2OFB(fbi);
   1018	int r;
   1019
   1020	DBG("set_par(%d)\n", FB2OFB(fbi)->id);
   1021
   1022	omapfb_get_mem_region(ofbi->region);
   1023
   1024	set_fb_fix(fbi);
   1025
   1026	r = setup_vrfb_rotation(fbi);
   1027	if (r)
   1028		goto out;
   1029
   1030	r = omapfb_apply_changes(fbi, 0);
   1031
   1032 out:
   1033	omapfb_put_mem_region(ofbi->region);
   1034
   1035	return r;
   1036}
   1037
   1038static int omapfb_pan_display(struct fb_var_screeninfo *var,
   1039		struct fb_info *fbi)
   1040{
   1041	struct omapfb_info *ofbi = FB2OFB(fbi);
   1042	struct fb_var_screeninfo new_var;
   1043	int r;
   1044
   1045	DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
   1046
   1047	if (var->xoffset == fbi->var.xoffset &&
   1048	    var->yoffset == fbi->var.yoffset)
   1049		return 0;
   1050
   1051	new_var = fbi->var;
   1052	new_var.xoffset = var->xoffset;
   1053	new_var.yoffset = var->yoffset;
   1054
   1055	fbi->var = new_var;
   1056
   1057	omapfb_get_mem_region(ofbi->region);
   1058
   1059	r = omapfb_apply_changes(fbi, 0);
   1060
   1061	omapfb_put_mem_region(ofbi->region);
   1062
   1063	return r;
   1064}
   1065
   1066static void mmap_user_open(struct vm_area_struct *vma)
   1067{
   1068	struct omapfb2_mem_region *rg = vma->vm_private_data;
   1069
   1070	omapfb_get_mem_region(rg);
   1071	atomic_inc(&rg->map_count);
   1072	omapfb_put_mem_region(rg);
   1073}
   1074
   1075static void mmap_user_close(struct vm_area_struct *vma)
   1076{
   1077	struct omapfb2_mem_region *rg = vma->vm_private_data;
   1078
   1079	omapfb_get_mem_region(rg);
   1080	atomic_dec(&rg->map_count);
   1081	omapfb_put_mem_region(rg);
   1082}
   1083
   1084static const struct vm_operations_struct mmap_user_ops = {
   1085	.open = mmap_user_open,
   1086	.close = mmap_user_close,
   1087};
   1088
   1089static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
   1090{
   1091	struct omapfb_info *ofbi = FB2OFB(fbi);
   1092	struct fb_fix_screeninfo *fix = &fbi->fix;
   1093	struct omapfb2_mem_region *rg;
   1094	unsigned long start;
   1095	u32 len;
   1096	int r;
   1097
   1098	rg = omapfb_get_mem_region(ofbi->region);
   1099
   1100	start = omapfb_get_region_paddr(ofbi);
   1101	len = fix->smem_len;
   1102
   1103	DBG("user mmap region start %lx, len %d, off %lx\n", start, len,
   1104			vma->vm_pgoff << PAGE_SHIFT);
   1105
   1106	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
   1107	vma->vm_ops = &mmap_user_ops;
   1108	vma->vm_private_data = rg;
   1109
   1110	r = vm_iomap_memory(vma, start, len);
   1111	if (r)
   1112		goto error;
   1113
   1114	/* vm_ops.open won't be called for mmap itself. */
   1115	atomic_inc(&rg->map_count);
   1116
   1117	omapfb_put_mem_region(rg);
   1118
   1119	return 0;
   1120
   1121error:
   1122	omapfb_put_mem_region(ofbi->region);
   1123
   1124	return r;
   1125}
   1126
   1127/* Store a single color palette entry into a pseudo palette or the hardware
   1128 * palette if one is available. For now we support only 16bpp and thus store
   1129 * the entry only to the pseudo palette.
   1130 */
   1131static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
   1132		u_int blue, u_int transp, int update_hw_pal)
   1133{
   1134	/*struct omapfb_info *ofbi = FB2OFB(fbi);*/
   1135	/*struct omapfb2_device *fbdev = ofbi->fbdev;*/
   1136	struct fb_var_screeninfo *var = &fbi->var;
   1137	int r = 0;
   1138
   1139	enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
   1140
   1141	/*switch (plane->color_mode) {*/
   1142	switch (mode) {
   1143	case OMAPFB_COLOR_YUV422:
   1144	case OMAPFB_COLOR_YUV420:
   1145	case OMAPFB_COLOR_YUY422:
   1146		r = -EINVAL;
   1147		break;
   1148	case OMAPFB_COLOR_CLUT_8BPP:
   1149	case OMAPFB_COLOR_CLUT_4BPP:
   1150	case OMAPFB_COLOR_CLUT_2BPP:
   1151	case OMAPFB_COLOR_CLUT_1BPP:
   1152		/*
   1153		   if (fbdev->ctrl->setcolreg)
   1154		   r = fbdev->ctrl->setcolreg(regno, red, green, blue,
   1155		   transp, update_hw_pal);
   1156		   */
   1157		r = -EINVAL;
   1158		break;
   1159	case OMAPFB_COLOR_RGB565:
   1160	case OMAPFB_COLOR_RGB444:
   1161	case OMAPFB_COLOR_RGB24P:
   1162	case OMAPFB_COLOR_RGB24U:
   1163		if (regno < 16) {
   1164			u32 pal;
   1165			pal = ((red >> (16 - var->red.length)) <<
   1166					var->red.offset) |
   1167				((green >> (16 - var->green.length)) <<
   1168				 var->green.offset) |
   1169				(blue >> (16 - var->blue.length));
   1170			((u32 *)(fbi->pseudo_palette))[regno] = pal;
   1171		}
   1172		break;
   1173	default:
   1174		BUG();
   1175	}
   1176	return r;
   1177}
   1178
   1179static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
   1180		u_int transp, struct fb_info *info)
   1181{
   1182	DBG("setcolreg\n");
   1183
   1184	return _setcolreg(info, regno, red, green, blue, transp, 1);
   1185}
   1186
   1187static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
   1188{
   1189	int count, index, r;
   1190	u16 *red, *green, *blue, *transp;
   1191	u16 trans = 0xffff;
   1192
   1193	DBG("setcmap\n");
   1194
   1195	red     = cmap->red;
   1196	green   = cmap->green;
   1197	blue    = cmap->blue;
   1198	transp  = cmap->transp;
   1199	index   = cmap->start;
   1200
   1201	for (count = 0; count < cmap->len; count++) {
   1202		if (transp)
   1203			trans = *transp++;
   1204		r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
   1205				count == cmap->len - 1);
   1206		if (r != 0)
   1207			return r;
   1208	}
   1209
   1210	return 0;
   1211}
   1212
   1213static int omapfb_blank(int blank, struct fb_info *fbi)
   1214{
   1215	struct omapfb_info *ofbi = FB2OFB(fbi);
   1216	struct omapfb2_device *fbdev = ofbi->fbdev;
   1217	struct omap_dss_device *display = fb2display(fbi);
   1218	struct omapfb_display_data *d;
   1219	int r = 0;
   1220
   1221	if (!display)
   1222		return -EINVAL;
   1223
   1224	omapfb_lock(fbdev);
   1225
   1226	d = get_display_data(fbdev, display);
   1227
   1228	switch (blank) {
   1229	case FB_BLANK_UNBLANK:
   1230		if (display->state == OMAP_DSS_DISPLAY_ACTIVE)
   1231			goto exit;
   1232
   1233		r = display->driver->enable(display);
   1234
   1235		if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
   1236				d->update_mode == OMAPFB_AUTO_UPDATE &&
   1237				!d->auto_update_work_enabled)
   1238			omapfb_start_auto_update(fbdev, display);
   1239
   1240		break;
   1241
   1242	case FB_BLANK_NORMAL:
   1243		/* FB_BLANK_NORMAL could be implemented.
   1244		 * Needs DSS additions. */
   1245	case FB_BLANK_VSYNC_SUSPEND:
   1246	case FB_BLANK_HSYNC_SUSPEND:
   1247	case FB_BLANK_POWERDOWN:
   1248		if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
   1249			goto exit;
   1250
   1251		if (d->auto_update_work_enabled)
   1252			omapfb_stop_auto_update(fbdev, display);
   1253
   1254		display->driver->disable(display);
   1255
   1256		break;
   1257
   1258	default:
   1259		r = -EINVAL;
   1260	}
   1261
   1262exit:
   1263	omapfb_unlock(fbdev);
   1264
   1265	return r;
   1266}
   1267
   1268#if 0
   1269/* XXX fb_read and fb_write are needed for VRFB */
   1270ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
   1271		size_t count, loff_t *ppos)
   1272{
   1273	DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
   1274	/* XXX needed for VRFB */
   1275	return count;
   1276}
   1277#endif
   1278
   1279static const struct fb_ops omapfb_ops = {
   1280	.owner          = THIS_MODULE,
   1281	.fb_open        = omapfb_open,
   1282	.fb_release     = omapfb_release,
   1283	.fb_fillrect    = cfb_fillrect,
   1284	.fb_copyarea    = cfb_copyarea,
   1285	.fb_imageblit   = cfb_imageblit,
   1286	.fb_blank       = omapfb_blank,
   1287	.fb_ioctl       = omapfb_ioctl,
   1288	.fb_check_var   = omapfb_check_var,
   1289	.fb_set_par     = omapfb_set_par,
   1290	.fb_pan_display = omapfb_pan_display,
   1291	.fb_mmap	= omapfb_mmap,
   1292	.fb_setcolreg	= omapfb_setcolreg,
   1293	.fb_setcmap	= omapfb_setcmap,
   1294	/*.fb_write	= omapfb_write,*/
   1295};
   1296
   1297static void omapfb_free_fbmem(struct fb_info *fbi)
   1298{
   1299	struct omapfb_info *ofbi = FB2OFB(fbi);
   1300	struct omapfb2_device *fbdev = ofbi->fbdev;
   1301	struct omapfb2_mem_region *rg;
   1302
   1303	rg = ofbi->region;
   1304
   1305	if (rg->token == NULL)
   1306		return;
   1307
   1308	WARN_ON(atomic_read(&rg->map_count));
   1309
   1310	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
   1311		/* unmap the 0 angle rotation */
   1312		if (rg->vrfb.vaddr[0]) {
   1313			iounmap(rg->vrfb.vaddr[0]);
   1314			rg->vrfb.vaddr[0] = NULL;
   1315		}
   1316
   1317		omap_vrfb_release_ctx(&rg->vrfb);
   1318	}
   1319
   1320	dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle,
   1321			rg->attrs);
   1322
   1323	rg->token = NULL;
   1324	rg->vaddr = NULL;
   1325	rg->paddr = 0;
   1326	rg->alloc = 0;
   1327	rg->size = 0;
   1328}
   1329
   1330static void clear_fb_info(struct fb_info *fbi)
   1331{
   1332	memset(&fbi->var, 0, sizeof(fbi->var));
   1333	memset(&fbi->fix, 0, sizeof(fbi->fix));
   1334	strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
   1335}
   1336
   1337static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
   1338{
   1339	int i;
   1340
   1341	DBG("free all fbmem\n");
   1342
   1343	for (i = 0; i < fbdev->num_fbs; i++) {
   1344		struct fb_info *fbi = fbdev->fbs[i];
   1345		omapfb_free_fbmem(fbi);
   1346		clear_fb_info(fbi);
   1347	}
   1348
   1349	return 0;
   1350}
   1351
   1352static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
   1353		unsigned long paddr)
   1354{
   1355	struct omapfb_info *ofbi = FB2OFB(fbi);
   1356	struct omapfb2_device *fbdev = ofbi->fbdev;
   1357	struct omapfb2_mem_region *rg;
   1358	void *token;
   1359	unsigned long attrs;
   1360	dma_addr_t dma_handle;
   1361	int r;
   1362
   1363	rg = ofbi->region;
   1364
   1365	rg->paddr = 0;
   1366	rg->vaddr = NULL;
   1367	memset(&rg->vrfb, 0, sizeof rg->vrfb);
   1368	rg->size = 0;
   1369	rg->type = 0;
   1370	rg->alloc = false;
   1371	rg->map = false;
   1372
   1373	size = PAGE_ALIGN(size);
   1374
   1375	attrs = DMA_ATTR_WRITE_COMBINE;
   1376
   1377	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
   1378		attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
   1379
   1380	DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
   1381
   1382	token = dma_alloc_attrs(fbdev->dev, size, &dma_handle,
   1383			GFP_KERNEL, attrs);
   1384
   1385	if (token == NULL) {
   1386		dev_err(fbdev->dev, "failed to allocate framebuffer\n");
   1387		return -ENOMEM;
   1388	}
   1389
   1390	DBG("allocated VRAM paddr %lx, vaddr %p\n",
   1391			(unsigned long)dma_handle, token);
   1392
   1393	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
   1394		r = omap_vrfb_request_ctx(&rg->vrfb);
   1395		if (r) {
   1396			dma_free_attrs(fbdev->dev, size, token, dma_handle,
   1397					attrs);
   1398			dev_err(fbdev->dev, "vrfb create ctx failed\n");
   1399			return r;
   1400		}
   1401	}
   1402
   1403	rg->attrs = attrs;
   1404	rg->token = token;
   1405	rg->dma_handle = dma_handle;
   1406
   1407	rg->paddr = (unsigned long)dma_handle;
   1408	rg->vaddr = (void __iomem *)token;
   1409	rg->size = size;
   1410	rg->alloc = 1;
   1411
   1412	return 0;
   1413}
   1414
   1415/* allocate fbmem using display resolution as reference */
   1416static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
   1417		unsigned long paddr)
   1418{
   1419	struct omapfb_info *ofbi = FB2OFB(fbi);
   1420	struct omapfb2_device *fbdev = ofbi->fbdev;
   1421	struct omap_dss_device *display;
   1422	int bytespp;
   1423
   1424	display =  fb2display(fbi);
   1425
   1426	if (!display)
   1427		return 0;
   1428
   1429	switch (omapfb_get_recommended_bpp(fbdev, display)) {
   1430	case 16:
   1431		bytespp = 2;
   1432		break;
   1433	case 24:
   1434		bytespp = 4;
   1435		break;
   1436	default:
   1437		bytespp = 4;
   1438		break;
   1439	}
   1440
   1441	if (!size) {
   1442		u16 w, h;
   1443
   1444		display->driver->get_resolution(display, &w, &h);
   1445
   1446		if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
   1447			size = max(omap_vrfb_min_phys_size(w, h, bytespp),
   1448					omap_vrfb_min_phys_size(h, w, bytespp));
   1449
   1450			DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
   1451					w * h * bytespp, size);
   1452		} else {
   1453			size = w * h * bytespp;
   1454		}
   1455	}
   1456
   1457	if (!size)
   1458		return 0;
   1459
   1460	return omapfb_alloc_fbmem(fbi, size, paddr);
   1461}
   1462
   1463static int omapfb_parse_vram_param(const char *param, int max_entries,
   1464		unsigned long *sizes, unsigned long *paddrs)
   1465{
   1466	unsigned int fbnum;
   1467	unsigned long size;
   1468	unsigned long paddr = 0;
   1469	char *p, *start;
   1470
   1471	start = (char *)param;
   1472
   1473	while (1) {
   1474		p = start;
   1475
   1476		fbnum = simple_strtoul(p, &p, 10);
   1477
   1478		if (p == start)
   1479			return -EINVAL;
   1480
   1481		if (*p != ':')
   1482			return -EINVAL;
   1483
   1484		if (fbnum >= max_entries)
   1485			return -EINVAL;
   1486
   1487		size = memparse(p + 1, &p);
   1488
   1489		if (!size)
   1490			return -EINVAL;
   1491
   1492		paddr = 0;
   1493
   1494		if (*p == '@') {
   1495			paddr = simple_strtoul(p + 1, &p, 16);
   1496
   1497			if (!paddr)
   1498				return -EINVAL;
   1499
   1500		}
   1501
   1502		WARN_ONCE(paddr,
   1503			"reserving memory at predefined address not supported\n");
   1504
   1505		paddrs[fbnum] = paddr;
   1506		sizes[fbnum] = size;
   1507
   1508		if (*p == 0)
   1509			break;
   1510
   1511		if (*p != ',')
   1512			return -EINVAL;
   1513
   1514		++p;
   1515
   1516		start = p;
   1517	}
   1518
   1519	return 0;
   1520}
   1521
   1522static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
   1523{
   1524	int i, r;
   1525	unsigned long vram_sizes[10];
   1526	unsigned long vram_paddrs[10];
   1527
   1528	memset(&vram_sizes, 0, sizeof(vram_sizes));
   1529	memset(&vram_paddrs, 0, sizeof(vram_paddrs));
   1530
   1531	if (def_vram &&	omapfb_parse_vram_param(def_vram, 10,
   1532				vram_sizes, vram_paddrs)) {
   1533		dev_err(fbdev->dev, "failed to parse vram parameter\n");
   1534
   1535		memset(&vram_sizes, 0, sizeof(vram_sizes));
   1536		memset(&vram_paddrs, 0, sizeof(vram_paddrs));
   1537	}
   1538
   1539	for (i = 0; i < fbdev->num_fbs; i++) {
   1540		/* allocate memory automatically only for fb0, or if
   1541		 * excplicitly defined with vram or plat data option */
   1542		if (i == 0 || vram_sizes[i] != 0) {
   1543			r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
   1544					vram_sizes[i], vram_paddrs[i]);
   1545
   1546			if (r)
   1547				return r;
   1548		}
   1549	}
   1550
   1551	for (i = 0; i < fbdev->num_fbs; i++) {
   1552		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
   1553		struct omapfb2_mem_region *rg;
   1554		rg = ofbi->region;
   1555
   1556		DBG("region%d phys %08x virt %p size=%lu\n",
   1557				i,
   1558				rg->paddr,
   1559				rg->vaddr,
   1560				rg->size);
   1561	}
   1562
   1563	return 0;
   1564}
   1565
   1566static void omapfb_clear_fb(struct fb_info *fbi)
   1567{
   1568	const struct fb_fillrect rect = {
   1569		.dx = 0,
   1570		.dy = 0,
   1571		.width = fbi->var.xres_virtual,
   1572		.height = fbi->var.yres_virtual,
   1573		.color = 0,
   1574		.rop = ROP_COPY,
   1575	};
   1576
   1577	cfb_fillrect(fbi, &rect);
   1578}
   1579
   1580int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
   1581{
   1582	struct omapfb_info *ofbi = FB2OFB(fbi);
   1583	struct omapfb2_device *fbdev = ofbi->fbdev;
   1584	struct omapfb2_mem_region *rg = ofbi->region;
   1585	unsigned long old_size = rg->size;
   1586	unsigned long old_paddr = rg->paddr;
   1587	int old_type = rg->type;
   1588	int r;
   1589
   1590	if (type != OMAPFB_MEMTYPE_SDRAM)
   1591		return -EINVAL;
   1592
   1593	size = PAGE_ALIGN(size);
   1594
   1595	if (old_size == size && old_type == type)
   1596		return 0;
   1597
   1598	omapfb_free_fbmem(fbi);
   1599
   1600	if (size == 0) {
   1601		clear_fb_info(fbi);
   1602		return 0;
   1603	}
   1604
   1605	r = omapfb_alloc_fbmem(fbi, size, 0);
   1606
   1607	if (r) {
   1608		if (old_size)
   1609			omapfb_alloc_fbmem(fbi, old_size, old_paddr);
   1610
   1611		if (rg->size == 0)
   1612			clear_fb_info(fbi);
   1613
   1614		return r;
   1615	}
   1616
   1617	if (old_size == size)
   1618		return 0;
   1619
   1620	if (old_size == 0) {
   1621		DBG("initializing fb %d\n", ofbi->id);
   1622		r = omapfb_fb_init(fbdev, fbi);
   1623		if (r) {
   1624			DBG("omapfb_fb_init failed\n");
   1625			goto err;
   1626		}
   1627		r = omapfb_apply_changes(fbi, 1);
   1628		if (r) {
   1629			DBG("omapfb_apply_changes failed\n");
   1630			goto err;
   1631		}
   1632	} else {
   1633		struct fb_var_screeninfo new_var;
   1634		memcpy(&new_var, &fbi->var, sizeof(new_var));
   1635		r = check_fb_var(fbi, &new_var);
   1636		if (r)
   1637			goto err;
   1638		memcpy(&fbi->var, &new_var, sizeof(fbi->var));
   1639		set_fb_fix(fbi);
   1640		r = setup_vrfb_rotation(fbi);
   1641		if (r)
   1642			goto err;
   1643	}
   1644
   1645	omapfb_clear_fb(fbi);
   1646
   1647	return 0;
   1648err:
   1649	omapfb_free_fbmem(fbi);
   1650	clear_fb_info(fbi);
   1651	return r;
   1652}
   1653
   1654static void omapfb_auto_update_work(struct work_struct *work)
   1655{
   1656	struct omap_dss_device *dssdev;
   1657	struct omap_dss_driver *dssdrv;
   1658	struct omapfb_display_data *d;
   1659	u16 w, h;
   1660	unsigned int freq;
   1661	struct omapfb2_device *fbdev;
   1662
   1663	d = container_of(work, struct omapfb_display_data,
   1664			auto_update_work.work);
   1665
   1666	dssdev = d->dssdev;
   1667	dssdrv = dssdev->driver;
   1668	fbdev = d->fbdev;
   1669
   1670	if (!dssdrv || !dssdrv->update)
   1671		return;
   1672
   1673	if (dssdrv->sync)
   1674		dssdrv->sync(dssdev);
   1675
   1676	dssdrv->get_resolution(dssdev, &w, &h);
   1677	dssdrv->update(dssdev, 0, 0, w, h);
   1678
   1679	freq = auto_update_freq;
   1680	if (freq == 0)
   1681		freq = 20;
   1682	queue_delayed_work(fbdev->auto_update_wq,
   1683			&d->auto_update_work, HZ / freq);
   1684}
   1685
   1686void omapfb_start_auto_update(struct omapfb2_device *fbdev,
   1687		struct omap_dss_device *display)
   1688{
   1689	struct omapfb_display_data *d;
   1690
   1691	if (fbdev->auto_update_wq == NULL) {
   1692		struct workqueue_struct *wq;
   1693
   1694		wq = create_singlethread_workqueue("omapfb_auto_update");
   1695
   1696		if (wq == NULL) {
   1697			dev_err(fbdev->dev, "Failed to create workqueue for "
   1698					"auto-update\n");
   1699			return;
   1700		}
   1701
   1702		fbdev->auto_update_wq = wq;
   1703	}
   1704
   1705	d = get_display_data(fbdev, display);
   1706
   1707	INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
   1708
   1709	d->auto_update_work_enabled = true;
   1710
   1711	omapfb_auto_update_work(&d->auto_update_work.work);
   1712}
   1713
   1714void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
   1715		struct omap_dss_device *display)
   1716{
   1717	struct omapfb_display_data *d;
   1718
   1719	d = get_display_data(fbdev, display);
   1720
   1721	cancel_delayed_work_sync(&d->auto_update_work);
   1722
   1723	d->auto_update_work_enabled = false;
   1724}
   1725
   1726/* initialize fb_info, var, fix to something sane based on the display */
   1727static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
   1728{
   1729	struct fb_var_screeninfo *var = &fbi->var;
   1730	struct omap_dss_device *display = fb2display(fbi);
   1731	struct omapfb_info *ofbi = FB2OFB(fbi);
   1732	int r = 0;
   1733
   1734	fbi->fbops = &omapfb_ops;
   1735	fbi->flags = FBINFO_FLAG_DEFAULT;
   1736	fbi->pseudo_palette = fbdev->pseudo_palette;
   1737
   1738	if (ofbi->region->size == 0) {
   1739		clear_fb_info(fbi);
   1740		return 0;
   1741	}
   1742
   1743	var->nonstd = 0;
   1744	var->bits_per_pixel = 0;
   1745
   1746	var->rotate = def_rotate;
   1747
   1748	if (display) {
   1749		u16 w, h;
   1750		int rotation = (var->rotate + ofbi->rotation[0]) % 4;
   1751
   1752		display->driver->get_resolution(display, &w, &h);
   1753
   1754		if (rotation == FB_ROTATE_CW ||
   1755				rotation == FB_ROTATE_CCW) {
   1756			var->xres = h;
   1757			var->yres = w;
   1758		} else {
   1759			var->xres = w;
   1760			var->yres = h;
   1761		}
   1762
   1763		var->xres_virtual = var->xres;
   1764		var->yres_virtual = var->yres;
   1765
   1766		if (!var->bits_per_pixel) {
   1767			switch (omapfb_get_recommended_bpp(fbdev, display)) {
   1768			case 16:
   1769				var->bits_per_pixel = 16;
   1770				break;
   1771			case 24:
   1772				var->bits_per_pixel = 32;
   1773				break;
   1774			default:
   1775				dev_err(fbdev->dev, "illegal display "
   1776						"bpp\n");
   1777				return -EINVAL;
   1778			}
   1779		}
   1780	} else {
   1781		/* if there's no display, let's just guess some basic values */
   1782		var->xres = 320;
   1783		var->yres = 240;
   1784		var->xres_virtual = var->xres;
   1785		var->yres_virtual = var->yres;
   1786		if (!var->bits_per_pixel)
   1787			var->bits_per_pixel = 16;
   1788	}
   1789
   1790	r = check_fb_var(fbi, var);
   1791	if (r)
   1792		goto err;
   1793
   1794	set_fb_fix(fbi);
   1795	r = setup_vrfb_rotation(fbi);
   1796	if (r)
   1797		goto err;
   1798
   1799	r = fb_alloc_cmap(&fbi->cmap, 256, 0);
   1800	if (r)
   1801		dev_err(fbdev->dev, "unable to allocate color map memory\n");
   1802
   1803err:
   1804	return r;
   1805}
   1806
   1807static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
   1808{
   1809	fb_dealloc_cmap(&fbi->cmap);
   1810}
   1811
   1812
   1813static void omapfb_free_resources(struct omapfb2_device *fbdev)
   1814{
   1815	int i;
   1816
   1817	DBG("free_resources\n");
   1818
   1819	if (fbdev == NULL)
   1820		return;
   1821
   1822	for (i = 0; i < fbdev->num_overlays; i++) {
   1823		struct omap_overlay *ovl = fbdev->overlays[i];
   1824
   1825		ovl->disable(ovl);
   1826
   1827		if (ovl->manager)
   1828			ovl->unset_manager(ovl);
   1829	}
   1830
   1831	for (i = 0; i < fbdev->num_fbs; i++)
   1832		unregister_framebuffer(fbdev->fbs[i]);
   1833
   1834	/* free the reserved fbmem */
   1835	omapfb_free_all_fbmem(fbdev);
   1836
   1837	for (i = 0; i < fbdev->num_fbs; i++) {
   1838		fbinfo_cleanup(fbdev, fbdev->fbs[i]);
   1839		framebuffer_release(fbdev->fbs[i]);
   1840	}
   1841
   1842	for (i = 0; i < fbdev->num_displays; i++) {
   1843		struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
   1844
   1845		if (fbdev->displays[i].auto_update_work_enabled)
   1846			omapfb_stop_auto_update(fbdev, dssdev);
   1847
   1848		if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
   1849			dssdev->driver->disable(dssdev);
   1850
   1851		dssdev->driver->disconnect(dssdev);
   1852
   1853		omap_dss_put_device(dssdev);
   1854	}
   1855
   1856	if (fbdev->auto_update_wq != NULL) {
   1857		destroy_workqueue(fbdev->auto_update_wq);
   1858		fbdev->auto_update_wq = NULL;
   1859	}
   1860
   1861	dev_set_drvdata(fbdev->dev, NULL);
   1862}
   1863
   1864static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
   1865{
   1866	int r, i;
   1867
   1868	fbdev->num_fbs = 0;
   1869
   1870	DBG("create %d framebuffers\n",	CONFIG_FB_OMAP2_NUM_FBS);
   1871
   1872	/* allocate fb_infos */
   1873	for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
   1874		struct fb_info *fbi;
   1875		struct omapfb_info *ofbi;
   1876
   1877		fbi = framebuffer_alloc(sizeof(struct omapfb_info),
   1878				fbdev->dev);
   1879		if (!fbi)
   1880			return -ENOMEM;
   1881
   1882		clear_fb_info(fbi);
   1883
   1884		fbdev->fbs[i] = fbi;
   1885
   1886		ofbi = FB2OFB(fbi);
   1887		ofbi->fbdev = fbdev;
   1888		ofbi->id = i;
   1889
   1890		ofbi->region = &fbdev->regions[i];
   1891		ofbi->region->id = i;
   1892		init_rwsem(&ofbi->region->lock);
   1893
   1894		/* assign these early, so that fb alloc can use them */
   1895		ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
   1896			OMAP_DSS_ROT_DMA;
   1897		ofbi->mirror = def_mirror;
   1898
   1899		fbdev->num_fbs++;
   1900	}
   1901
   1902	DBG("fb_infos allocated\n");
   1903
   1904	/* assign overlays for the fbs */
   1905	for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
   1906		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
   1907
   1908		ofbi->overlays[0] = fbdev->overlays[i];
   1909		ofbi->num_overlays = 1;
   1910	}
   1911
   1912	/* allocate fb memories */
   1913	r = omapfb_allocate_all_fbs(fbdev);
   1914	if (r) {
   1915		dev_err(fbdev->dev, "failed to allocate fbmem\n");
   1916		return r;
   1917	}
   1918
   1919	DBG("fbmems allocated\n");
   1920
   1921	/* setup fb_infos */
   1922	for (i = 0; i < fbdev->num_fbs; i++) {
   1923		struct fb_info *fbi = fbdev->fbs[i];
   1924		struct omapfb_info *ofbi = FB2OFB(fbi);
   1925
   1926		omapfb_get_mem_region(ofbi->region);
   1927		r = omapfb_fb_init(fbdev, fbi);
   1928		omapfb_put_mem_region(ofbi->region);
   1929
   1930		if (r) {
   1931			dev_err(fbdev->dev, "failed to setup fb_info\n");
   1932			return r;
   1933		}
   1934	}
   1935
   1936	for (i = 0; i < fbdev->num_fbs; i++) {
   1937		struct fb_info *fbi = fbdev->fbs[i];
   1938		struct omapfb_info *ofbi = FB2OFB(fbi);
   1939
   1940		if (ofbi->region->size == 0)
   1941			continue;
   1942
   1943		omapfb_clear_fb(fbi);
   1944	}
   1945
   1946	DBG("fb_infos initialized\n");
   1947
   1948	for (i = 0; i < fbdev->num_fbs; i++) {
   1949		r = register_framebuffer(fbdev->fbs[i]);
   1950		if (r != 0) {
   1951			dev_err(fbdev->dev,
   1952				"registering framebuffer %d failed\n", i);
   1953			return r;
   1954		}
   1955	}
   1956
   1957	DBG("framebuffers registered\n");
   1958
   1959	for (i = 0; i < fbdev->num_fbs; i++) {
   1960		struct fb_info *fbi = fbdev->fbs[i];
   1961		struct omapfb_info *ofbi = FB2OFB(fbi);
   1962
   1963		omapfb_get_mem_region(ofbi->region);
   1964		r = omapfb_apply_changes(fbi, 1);
   1965		omapfb_put_mem_region(ofbi->region);
   1966
   1967		if (r) {
   1968			dev_err(fbdev->dev, "failed to change mode\n");
   1969			return r;
   1970		}
   1971	}
   1972
   1973	/* Enable fb0 */
   1974	if (fbdev->num_fbs > 0) {
   1975		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
   1976
   1977		if (ofbi->num_overlays > 0) {
   1978			struct omap_overlay *ovl = ofbi->overlays[0];
   1979
   1980			ovl->manager->apply(ovl->manager);
   1981
   1982			r = omapfb_overlay_enable(ovl, 1);
   1983
   1984			if (r) {
   1985				dev_err(fbdev->dev,
   1986						"failed to enable overlay\n");
   1987				return r;
   1988			}
   1989		}
   1990	}
   1991
   1992	DBG("create_framebuffers done\n");
   1993
   1994	return 0;
   1995}
   1996
   1997static int omapfb_mode_to_timings(const char *mode_str,
   1998		struct omap_dss_device *display,
   1999		struct omap_video_timings *timings, u8 *bpp)
   2000{
   2001	struct fb_info *fbi;
   2002	struct fb_var_screeninfo *var;
   2003	struct fb_ops *fbops;
   2004	int r;
   2005
   2006#ifdef CONFIG_OMAP2_DSS_VENC
   2007	if (strcmp(mode_str, "pal") == 0) {
   2008		*timings = omap_dss_pal_timings;
   2009		*bpp = 24;
   2010		return 0;
   2011	} else if (strcmp(mode_str, "ntsc") == 0) {
   2012		*timings = omap_dss_ntsc_timings;
   2013		*bpp = 24;
   2014		return 0;
   2015	}
   2016#endif
   2017
   2018	/* this is quite a hack, but I wanted to use the modedb and for
   2019	 * that we need fb_info and var, so we create dummy ones */
   2020
   2021	*bpp = 0;
   2022	fbi = NULL;
   2023	var = NULL;
   2024	fbops = NULL;
   2025
   2026	fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
   2027	if (fbi == NULL) {
   2028		r = -ENOMEM;
   2029		goto err;
   2030	}
   2031
   2032	var = kzalloc(sizeof(*var), GFP_KERNEL);
   2033	if (var == NULL) {
   2034		r = -ENOMEM;
   2035		goto err;
   2036	}
   2037
   2038	fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
   2039	if (fbops == NULL) {
   2040		r = -ENOMEM;
   2041		goto err;
   2042	}
   2043
   2044	fbi->fbops = fbops;
   2045
   2046	r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
   2047	if (r == 0) {
   2048		r = -EINVAL;
   2049		goto err;
   2050	}
   2051
   2052	if (display->driver->get_timings) {
   2053		display->driver->get_timings(display, timings);
   2054	} else {
   2055		timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
   2056		timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
   2057		timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
   2058	}
   2059
   2060	timings->pixelclock = PICOS2KHZ(var->pixclock) * 1000;
   2061	timings->hbp = var->left_margin;
   2062	timings->hfp = var->right_margin;
   2063	timings->vbp = var->upper_margin;
   2064	timings->vfp = var->lower_margin;
   2065	timings->hsw = var->hsync_len;
   2066	timings->vsw = var->vsync_len;
   2067	timings->x_res = var->xres;
   2068	timings->y_res = var->yres;
   2069	timings->hsync_level = var->sync & FB_SYNC_HOR_HIGH_ACT ?
   2070				OMAPDSS_SIG_ACTIVE_HIGH :
   2071				OMAPDSS_SIG_ACTIVE_LOW;
   2072	timings->vsync_level = var->sync & FB_SYNC_VERT_HIGH_ACT ?
   2073				OMAPDSS_SIG_ACTIVE_HIGH :
   2074				OMAPDSS_SIG_ACTIVE_LOW;
   2075	timings->interlace = var->vmode & FB_VMODE_INTERLACED;
   2076
   2077	switch (var->bits_per_pixel) {
   2078	case 16:
   2079		*bpp = 16;
   2080		break;
   2081	case 24:
   2082	case 32:
   2083	default:
   2084		*bpp = 24;
   2085		break;
   2086	}
   2087
   2088	r = 0;
   2089
   2090err:
   2091	kfree(fbi);
   2092	kfree(var);
   2093	kfree(fbops);
   2094
   2095	return r;
   2096}
   2097
   2098static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
   2099		struct omap_dss_device *display, char *mode_str)
   2100{
   2101	int r;
   2102	u8 bpp;
   2103	struct omap_video_timings timings, temp_timings;
   2104	struct omapfb_display_data *d;
   2105
   2106	r = omapfb_mode_to_timings(mode_str, display, &timings, &bpp);
   2107	if (r)
   2108		return r;
   2109
   2110	d = get_display_data(fbdev, display);
   2111	d->bpp_override = bpp;
   2112
   2113	if (display->driver->check_timings) {
   2114		r = display->driver->check_timings(display, &timings);
   2115		if (r)
   2116			return r;
   2117	} else {
   2118		/* If check_timings is not present compare xres and yres */
   2119		if (display->driver->get_timings) {
   2120			display->driver->get_timings(display, &temp_timings);
   2121
   2122			if (temp_timings.x_res != timings.x_res ||
   2123				temp_timings.y_res != timings.y_res)
   2124				return -EINVAL;
   2125		}
   2126	}
   2127
   2128	if (display->driver->set_timings)
   2129			display->driver->set_timings(display, &timings);
   2130
   2131	return 0;
   2132}
   2133
   2134static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
   2135		struct omap_dss_device *dssdev)
   2136{
   2137	struct omapfb_display_data *d;
   2138
   2139	BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
   2140
   2141	d = get_display_data(fbdev, dssdev);
   2142
   2143	if (d->bpp_override != 0)
   2144		return d->bpp_override;
   2145
   2146	return dssdev->driver->get_recommended_bpp(dssdev);
   2147}
   2148
   2149static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
   2150{
   2151	char *str, *options, *this_opt;
   2152	int r = 0;
   2153
   2154	str = kstrdup(def_mode, GFP_KERNEL);
   2155	if (!str)
   2156		return -ENOMEM;
   2157	options = str;
   2158
   2159	while (!r && (this_opt = strsep(&options, ",")) != NULL) {
   2160		char *p, *display_str, *mode_str;
   2161		struct omap_dss_device *display;
   2162		int i;
   2163
   2164		p = strchr(this_opt, ':');
   2165		if (!p) {
   2166			r = -EINVAL;
   2167			break;
   2168		}
   2169
   2170		*p = 0;
   2171		display_str = this_opt;
   2172		mode_str = p + 1;
   2173
   2174		display = NULL;
   2175		for (i = 0; i < fbdev->num_displays; ++i) {
   2176			if (strcmp(fbdev->displays[i].dssdev->name,
   2177						display_str) == 0) {
   2178				display = fbdev->displays[i].dssdev;
   2179				break;
   2180			}
   2181		}
   2182
   2183		if (!display) {
   2184			r = -EINVAL;
   2185			break;
   2186		}
   2187
   2188		r = omapfb_set_def_mode(fbdev, display, mode_str);
   2189		if (r)
   2190			break;
   2191	}
   2192
   2193	kfree(str);
   2194
   2195	return r;
   2196}
   2197
   2198static void fb_videomode_to_omap_timings(struct fb_videomode *m,
   2199		struct omap_dss_device *display,
   2200		struct omap_video_timings *t)
   2201{
   2202	if (display->driver->get_timings) {
   2203		display->driver->get_timings(display, t);
   2204	} else {
   2205		t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
   2206		t->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
   2207		t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
   2208	}
   2209
   2210	t->x_res = m->xres;
   2211	t->y_res = m->yres;
   2212	t->pixelclock = PICOS2KHZ(m->pixclock) * 1000;
   2213	t->hsw = m->hsync_len;
   2214	t->hfp = m->right_margin;
   2215	t->hbp = m->left_margin;
   2216	t->vsw = m->vsync_len;
   2217	t->vfp = m->lower_margin;
   2218	t->vbp = m->upper_margin;
   2219	t->hsync_level = m->sync & FB_SYNC_HOR_HIGH_ACT ?
   2220				OMAPDSS_SIG_ACTIVE_HIGH :
   2221				OMAPDSS_SIG_ACTIVE_LOW;
   2222	t->vsync_level = m->sync & FB_SYNC_VERT_HIGH_ACT ?
   2223				OMAPDSS_SIG_ACTIVE_HIGH :
   2224				OMAPDSS_SIG_ACTIVE_LOW;
   2225	t->interlace = m->vmode & FB_VMODE_INTERLACED;
   2226}
   2227
   2228static int omapfb_find_best_mode(struct omap_dss_device *display,
   2229		struct omap_video_timings *timings)
   2230{
   2231	struct fb_monspecs *specs;
   2232	u8 *edid;
   2233	int r, i, best_idx, len;
   2234
   2235	if (!display->driver->read_edid)
   2236		return -ENODEV;
   2237
   2238	len = 0x80 * 2;
   2239	edid = kmalloc(len, GFP_KERNEL);
   2240	if (edid == NULL)
   2241		return -ENOMEM;
   2242
   2243	r = display->driver->read_edid(display, edid, len);
   2244	if (r < 0)
   2245		goto err1;
   2246
   2247	specs = kzalloc(sizeof(*specs), GFP_KERNEL);
   2248	if (specs == NULL) {
   2249		r = -ENOMEM;
   2250		goto err1;
   2251	}
   2252
   2253	fb_edid_to_monspecs(edid, specs);
   2254
   2255	best_idx = -1;
   2256
   2257	for (i = 0; i < specs->modedb_len; ++i) {
   2258		struct fb_videomode *m;
   2259		struct omap_video_timings t;
   2260
   2261		m = &specs->modedb[i];
   2262
   2263		if (m->pixclock == 0)
   2264			continue;
   2265
   2266		/* skip repeated pixel modes */
   2267		if (m->xres == 2880 || m->xres == 1440)
   2268			continue;
   2269
   2270		if (m->vmode & FB_VMODE_INTERLACED ||
   2271				m->vmode & FB_VMODE_DOUBLE)
   2272			continue;
   2273
   2274		fb_videomode_to_omap_timings(m, display, &t);
   2275
   2276		r = display->driver->check_timings(display, &t);
   2277		if (r == 0) {
   2278			best_idx = i;
   2279			break;
   2280		}
   2281	}
   2282
   2283	if (best_idx == -1) {
   2284		r = -ENOENT;
   2285		goto err2;
   2286	}
   2287
   2288	fb_videomode_to_omap_timings(&specs->modedb[best_idx], display,
   2289		timings);
   2290
   2291	r = 0;
   2292
   2293err2:
   2294	fb_destroy_modedb(specs->modedb);
   2295	kfree(specs);
   2296err1:
   2297	kfree(edid);
   2298
   2299	return r;
   2300}
   2301
   2302static int omapfb_init_display(struct omapfb2_device *fbdev,
   2303		struct omap_dss_device *dssdev)
   2304{
   2305	struct omap_dss_driver *dssdrv = dssdev->driver;
   2306	struct omapfb_display_data *d;
   2307	int r;
   2308
   2309	r = dssdrv->enable(dssdev);
   2310	if (r) {
   2311		dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
   2312				dssdev->name);
   2313		return r;
   2314	}
   2315
   2316	d = get_display_data(fbdev, dssdev);
   2317
   2318	d->fbdev = fbdev;
   2319
   2320	if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
   2321		u16 w, h;
   2322
   2323		if (auto_update) {
   2324			omapfb_start_auto_update(fbdev, dssdev);
   2325			d->update_mode = OMAPFB_AUTO_UPDATE;
   2326		} else {
   2327			d->update_mode = OMAPFB_MANUAL_UPDATE;
   2328		}
   2329
   2330		if (dssdrv->enable_te) {
   2331			r = dssdrv->enable_te(dssdev, 1);
   2332			if (r) {
   2333				dev_err(fbdev->dev, "Failed to set TE\n");
   2334				return r;
   2335			}
   2336		}
   2337
   2338		dssdrv->get_resolution(dssdev, &w, &h);
   2339		r = dssdrv->update(dssdev, 0, 0, w, h);
   2340		if (r) {
   2341			dev_err(fbdev->dev,
   2342					"Failed to update display\n");
   2343			return r;
   2344		}
   2345	} else {
   2346		d->update_mode = OMAPFB_AUTO_UPDATE;
   2347	}
   2348
   2349	return 0;
   2350}
   2351
   2352static int omapfb_init_connections(struct omapfb2_device *fbdev,
   2353		struct omap_dss_device *def_dssdev)
   2354{
   2355	int i, r;
   2356	struct omap_overlay_manager *mgr;
   2357
   2358	r = def_dssdev->driver->connect(def_dssdev);
   2359	if (r) {
   2360		dev_err(fbdev->dev, "failed to connect default display\n");
   2361		return r;
   2362	}
   2363
   2364	for (i = 0; i < fbdev->num_displays; ++i) {
   2365		struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
   2366
   2367		if (dssdev == def_dssdev)
   2368			continue;
   2369
   2370		/*
   2371		 * We don't care if the connect succeeds or not. We just want to
   2372		 * connect as many displays as possible.
   2373		 */
   2374		dssdev->driver->connect(dssdev);
   2375	}
   2376
   2377	mgr = omapdss_find_mgr_from_display(def_dssdev);
   2378
   2379	if (!mgr) {
   2380		dev_err(fbdev->dev, "no ovl manager for the default display\n");
   2381		return -EINVAL;
   2382	}
   2383
   2384	for (i = 0; i < fbdev->num_overlays; i++) {
   2385		struct omap_overlay *ovl = fbdev->overlays[i];
   2386
   2387		if (ovl->manager)
   2388			ovl->unset_manager(ovl);
   2389
   2390		r = ovl->set_manager(ovl, mgr);
   2391		if (r)
   2392			dev_warn(fbdev->dev,
   2393					"failed to connect overlay %s to manager %s\n",
   2394					ovl->name, mgr->name);
   2395	}
   2396
   2397	return 0;
   2398}
   2399
   2400static struct omap_dss_device *
   2401omapfb_find_default_display(struct omapfb2_device *fbdev)
   2402{
   2403	const char *def_name;
   2404	int i;
   2405
   2406	/*
   2407	 * Search with the display name from the user or the board file,
   2408	 * comparing to display names and aliases
   2409	 */
   2410
   2411	def_name = omapdss_get_default_display_name();
   2412
   2413	if (def_name) {
   2414		for (i = 0; i < fbdev->num_displays; ++i) {
   2415			struct omap_dss_device *dssdev;
   2416
   2417			dssdev = fbdev->displays[i].dssdev;
   2418
   2419			if (dssdev->name && strcmp(def_name, dssdev->name) == 0)
   2420				return dssdev;
   2421
   2422			if (strcmp(def_name, dssdev->alias) == 0)
   2423				return dssdev;
   2424		}
   2425
   2426		/* def_name given but not found */
   2427		return NULL;
   2428	}
   2429
   2430	/* then look for DT alias display0 */
   2431	for (i = 0; i < fbdev->num_displays; ++i) {
   2432		struct omap_dss_device *dssdev;
   2433		int id;
   2434
   2435		dssdev = fbdev->displays[i].dssdev;
   2436
   2437		if (dssdev->dev->of_node == NULL)
   2438			continue;
   2439
   2440		id = of_alias_get_id(dssdev->dev->of_node, "display");
   2441		if (id == 0)
   2442			return dssdev;
   2443	}
   2444
   2445	/* return the first display we have in the list */
   2446	return fbdev->displays[0].dssdev;
   2447}
   2448
   2449static int omapfb_probe(struct platform_device *pdev)
   2450{
   2451	struct omapfb2_device *fbdev = NULL;
   2452	int r = 0;
   2453	int i;
   2454	struct omap_dss_device *def_display;
   2455	struct omap_dss_device *dssdev;
   2456
   2457	DBG("omapfb_probe\n");
   2458
   2459	if (omapdss_is_initialized() == false)
   2460		return -EPROBE_DEFER;
   2461
   2462	if (pdev->num_resources != 0) {
   2463		dev_err(&pdev->dev, "probed for an unknown device\n");
   2464		r = -ENODEV;
   2465		goto err0;
   2466	}
   2467
   2468	fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device),
   2469			GFP_KERNEL);
   2470	if (fbdev == NULL) {
   2471		r = -ENOMEM;
   2472		goto err0;
   2473	}
   2474
   2475	if (def_vrfb && !omap_vrfb_supported()) {
   2476		def_vrfb = 0;
   2477		dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
   2478				"ignoring the module parameter vrfb=y\n");
   2479	}
   2480
   2481	r = omapdss_compat_init();
   2482	if (r)
   2483		goto err0;
   2484
   2485	mutex_init(&fbdev->mtx);
   2486
   2487	fbdev->dev = &pdev->dev;
   2488	platform_set_drvdata(pdev, fbdev);
   2489
   2490	fbdev->num_displays = 0;
   2491	dssdev = NULL;
   2492	for_each_dss_dev(dssdev) {
   2493		struct omapfb_display_data *d;
   2494
   2495		omap_dss_get_device(dssdev);
   2496
   2497		if (!dssdev->driver) {
   2498			dev_warn(&pdev->dev, "no driver for display: %s\n",
   2499				dssdev->name);
   2500			omap_dss_put_device(dssdev);
   2501			continue;
   2502		}
   2503
   2504		d = &fbdev->displays[fbdev->num_displays++];
   2505		d->dssdev = dssdev;
   2506		if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
   2507			d->update_mode = OMAPFB_MANUAL_UPDATE;
   2508		else
   2509			d->update_mode = OMAPFB_AUTO_UPDATE;
   2510	}
   2511
   2512	if (fbdev->num_displays == 0) {
   2513		dev_err(&pdev->dev, "no displays\n");
   2514		r = -EPROBE_DEFER;
   2515		goto cleanup;
   2516	}
   2517
   2518	fbdev->num_overlays = omap_dss_get_num_overlays();
   2519	for (i = 0; i < fbdev->num_overlays; i++)
   2520		fbdev->overlays[i] = omap_dss_get_overlay(i);
   2521
   2522	fbdev->num_managers = omap_dss_get_num_overlay_managers();
   2523	for (i = 0; i < fbdev->num_managers; i++)
   2524		fbdev->managers[i] = omap_dss_get_overlay_manager(i);
   2525
   2526	def_display = omapfb_find_default_display(fbdev);
   2527	if (def_display == NULL) {
   2528		dev_err(fbdev->dev, "failed to find default display\n");
   2529		r = -EPROBE_DEFER;
   2530		goto cleanup;
   2531	}
   2532
   2533	r = omapfb_init_connections(fbdev, def_display);
   2534	if (r) {
   2535		dev_err(fbdev->dev, "failed to init overlay connections\n");
   2536		goto cleanup;
   2537	}
   2538
   2539	if (def_mode && strlen(def_mode) > 0) {
   2540		if (omapfb_parse_def_modes(fbdev))
   2541			dev_warn(&pdev->dev, "cannot parse default modes\n");
   2542	} else if (def_display && def_display->driver->set_timings &&
   2543			def_display->driver->check_timings) {
   2544		struct omap_video_timings t;
   2545
   2546		r = omapfb_find_best_mode(def_display, &t);
   2547
   2548		if (r == 0)
   2549			def_display->driver->set_timings(def_display, &t);
   2550	}
   2551
   2552	r = omapfb_create_framebuffers(fbdev);
   2553	if (r)
   2554		goto cleanup;
   2555
   2556	for (i = 0; i < fbdev->num_managers; i++) {
   2557		struct omap_overlay_manager *mgr;
   2558		mgr = fbdev->managers[i];
   2559		r = mgr->apply(mgr);
   2560		if (r)
   2561			dev_warn(fbdev->dev, "failed to apply dispc config\n");
   2562	}
   2563
   2564	DBG("mgr->apply'ed\n");
   2565
   2566	if (def_display) {
   2567		r = omapfb_init_display(fbdev, def_display);
   2568		if (r) {
   2569			dev_err(fbdev->dev,
   2570					"failed to initialize default "
   2571					"display\n");
   2572			goto cleanup;
   2573		}
   2574	}
   2575
   2576	DBG("create sysfs for fbs\n");
   2577	r = omapfb_create_sysfs(fbdev);
   2578	if (r) {
   2579		dev_err(fbdev->dev, "failed to create sysfs entries\n");
   2580		goto cleanup;
   2581	}
   2582
   2583	if (def_display) {
   2584		u16 w, h;
   2585
   2586		def_display->driver->get_resolution(def_display, &w, &h);
   2587
   2588		dev_info(fbdev->dev, "using display '%s' mode %dx%d\n",
   2589			def_display->name, w, h);
   2590	}
   2591
   2592	return 0;
   2593
   2594cleanup:
   2595	omapfb_free_resources(fbdev);
   2596	omapdss_compat_uninit();
   2597err0:
   2598	dev_err(&pdev->dev, "failed to setup omapfb\n");
   2599	return r;
   2600}
   2601
   2602static int omapfb_remove(struct platform_device *pdev)
   2603{
   2604	struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
   2605
   2606	/* FIXME: wait till completion of pending events */
   2607
   2608	omapfb_remove_sysfs(fbdev);
   2609
   2610	omapfb_free_resources(fbdev);
   2611
   2612	omapdss_compat_uninit();
   2613
   2614	return 0;
   2615}
   2616
   2617static struct platform_driver omapfb_driver = {
   2618	.probe		= omapfb_probe,
   2619	.remove         = omapfb_remove,
   2620	.driver         = {
   2621		.name   = "omapfb",
   2622	},
   2623};
   2624
   2625module_param_named(mode, def_mode, charp, 0);
   2626module_param_named(vram, def_vram, charp, 0);
   2627module_param_named(rotate, def_rotate, int, 0);
   2628module_param_named(vrfb, def_vrfb, bool, 0);
   2629module_param_named(mirror, def_mirror, bool, 0);
   2630
   2631module_platform_driver(omapfb_driver);
   2632
   2633MODULE_ALIAS("platform:omapfb");
   2634MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
   2635MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
   2636MODULE_LICENSE("GPL v2");