PageRenderTime 286ms CodeModel.GetById 17ms app.highlight 240ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/video/omap2/omapfb/omapfb-main.c

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