Linux Audio

Check our new training course

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