PageRenderTime 542ms CodeModel.GetById 14ms app.highlight 360ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
C | 2506 lines | 1950 code | 446 blank | 110 comment | 448 complexity | 5661e5f3721ede936da396b5fb79743e MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

   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#include <linux/wait.h>
  33
  34#include <video/omapdss.h>
  35#include <plat/vram.h>
  36#include <plat/vrfb.h>
  37
  38#include "omapfb.h"
  39
  40#define MODULE_NAME     "omapfb"
  41
  42#define OMAPFB_PLANE_XRES_MIN		8
  43#define OMAPFB_PLANE_YRES_MIN		8
  44
  45static char *def_mode;
  46static char *def_vram;
  47static int def_vrfb;
  48static int def_rotate;
  49static int def_mirror;
  50
  51#ifdef DEBUG
  52unsigned int omapfb_debug;
  53module_param_named(debug, omapfb_debug, bool, 0644);
  54static unsigned int omapfb_test_pattern;
  55module_param_named(test, omapfb_test_pattern, bool, 0644);
  56#endif
  57
  58static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
  59static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
  60		struct omap_dss_device *dssdev);
  61
  62#ifdef DEBUG
  63static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
  64{
  65	struct fb_var_screeninfo *var = &fbi->var;
  66	struct fb_fix_screeninfo *fix = &fbi->fix;
  67	void __iomem *addr = fbi->screen_base;
  68	const unsigned bytespp = var->bits_per_pixel >> 3;
  69	const unsigned line_len = fix->line_length / bytespp;
  70
  71	int r = (color >> 16) & 0xff;
  72	int g = (color >> 8) & 0xff;
  73	int b = (color >> 0) & 0xff;
  74
  75	if (var->bits_per_pixel == 16) {
  76		u16 __iomem *p = (u16 __iomem *)addr;
  77		p += y * line_len + x;
  78
  79		r = r * 32 / 256;
  80		g = g * 64 / 256;
  81		b = b * 32 / 256;
  82
  83		__raw_writew((r << 11) | (g << 5) | (b << 0), p);
  84	} else if (var->bits_per_pixel == 24) {
  85		u8 __iomem *p = (u8 __iomem *)addr;
  86		p += (y * line_len + x) * 3;
  87
  88		__raw_writeb(b, p + 0);
  89		__raw_writeb(g, p + 1);
  90		__raw_writeb(r, p + 2);
  91	} else if (var->bits_per_pixel == 32) {
  92		u32 __iomem *p = (u32 __iomem *)addr;
  93		p += y * line_len + x;
  94		__raw_writel(color, p);
  95	}
  96}
  97
  98static void fill_fb(struct fb_info *fbi)
  99{
 100	struct fb_var_screeninfo *var = &fbi->var;
 101	const short w = var->xres_virtual;
 102	const short h = var->yres_virtual;
 103	void __iomem *addr = fbi->screen_base;
 104	int y, x;
 105
 106	if (!addr)
 107		return;
 108
 109	DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
 110
 111	for (y = 0; y < h; y++) {
 112		for (x = 0; x < w; x++) {
 113			if (x < 20 && y < 20)
 114				draw_pixel(fbi, x, y, 0xffffff);
 115			else if (x < 20 && (y > 20 && y < h - 20))
 116				draw_pixel(fbi, x, y, 0xff);
 117			else if (y < 20 && (x > 20 && x < w - 20))
 118				draw_pixel(fbi, x, y, 0xff00);
 119			else if (x > w - 20 && (y > 20 && y < h - 20))
 120				draw_pixel(fbi, x, y, 0xff0000);
 121			else if (y > h - 20 && (x > 20 && x < w - 20))
 122				draw_pixel(fbi, x, y, 0xffff00);
 123			else if (x == 20 || x == w - 20 ||
 124					y == 20 || y == h - 20)
 125				draw_pixel(fbi, x, y, 0xffffff);
 126			else if (x == y || w - x == h - y)
 127				draw_pixel(fbi, x, y, 0xff00ff);
 128			else if (w - x == y || x == h - y)
 129				draw_pixel(fbi, x, y, 0x00ffff);
 130			else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
 131				int t = x * 3 / w;
 132				unsigned r = 0, g = 0, b = 0;
 133				unsigned c;
 134				if (var->bits_per_pixel == 16) {
 135					if (t == 0)
 136						b = (y % 32) * 256 / 32;
 137					else if (t == 1)
 138						g = (y % 64) * 256 / 64;
 139					else if (t == 2)
 140						r = (y % 32) * 256 / 32;
 141				} else {
 142					if (t == 0)
 143						b = (y % 256);
 144					else if (t == 1)
 145						g = (y % 256);
 146					else if (t == 2)
 147						r = (y % 256);
 148				}
 149				c = (r << 16) | (g << 8) | (b << 0);
 150				draw_pixel(fbi, x, y, c);
 151			} else {
 152				draw_pixel(fbi, x, y, 0);
 153			}
 154		}
 155	}
 156}
 157#endif
 158
 159static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
 160{
 161	const struct vrfb *vrfb = &ofbi->region->vrfb;
 162	unsigned offset;
 163
 164	switch (rot) {
 165	case FB_ROTATE_UR:
 166		offset = 0;
 167		break;
 168	case FB_ROTATE_CW:
 169		offset = vrfb->yoffset;
 170		break;
 171	case FB_ROTATE_UD:
 172		offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
 173		break;
 174	case FB_ROTATE_CCW:
 175		offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
 176		break;
 177	default:
 178		BUG();
 179	}
 180
 181	offset *= vrfb->bytespp;
 182
 183	return offset;
 184}
 185
 186static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
 187{
 188	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
 189		return ofbi->region->vrfb.paddr[rot]
 190			+ omapfb_get_vrfb_offset(ofbi, rot);
 191	} else {
 192		return ofbi->region->paddr;
 193	}
 194}
 195
 196static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
 197{
 198	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
 199		return ofbi->region->vrfb.paddr[0];
 200	else
 201		return ofbi->region->paddr;
 202}
 203
 204static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
 205{
 206	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
 207		return ofbi->region->vrfb.vaddr[0];
 208	else
 209		return ofbi->region->vaddr;
 210}
 211
 212static struct omapfb_colormode omapfb_colormodes[] = {
 213	{
 214		.dssmode = OMAP_DSS_COLOR_UYVY,
 215		.bits_per_pixel = 16,
 216		.nonstd = OMAPFB_COLOR_YUV422,
 217	}, {
 218		.dssmode = OMAP_DSS_COLOR_YUV2,
 219		.bits_per_pixel = 16,
 220		.nonstd = OMAPFB_COLOR_YUY422,
 221	}, {
 222		.dssmode = OMAP_DSS_COLOR_ARGB16,
 223		.bits_per_pixel = 16,
 224		.red	= { .length = 4, .offset = 8, .msb_right = 0 },
 225		.green	= { .length = 4, .offset = 4, .msb_right = 0 },
 226		.blue	= { .length = 4, .offset = 0, .msb_right = 0 },
 227		.transp	= { .length = 4, .offset = 12, .msb_right = 0 },
 228	}, {
 229		.dssmode = OMAP_DSS_COLOR_RGB16,
 230		.bits_per_pixel = 16,
 231		.red	= { .length = 5, .offset = 11, .msb_right = 0 },
 232		.green	= { .length = 6, .offset = 5, .msb_right = 0 },
 233		.blue	= { .length = 5, .offset = 0, .msb_right = 0 },
 234		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
 235	}, {
 236		.dssmode = OMAP_DSS_COLOR_RGB24P,
 237		.bits_per_pixel = 24,
 238		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
 239		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
 240		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
 241		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
 242	}, {
 243		.dssmode = OMAP_DSS_COLOR_RGB24U,
 244		.bits_per_pixel = 32,
 245		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
 246		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
 247		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
 248		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
 249	}, {
 250		.dssmode = OMAP_DSS_COLOR_ARGB32,
 251		.bits_per_pixel = 32,
 252		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
 253		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
 254		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
 255		.transp	= { .length = 8, .offset = 24, .msb_right = 0 },
 256	}, {
 257		.dssmode = OMAP_DSS_COLOR_RGBA32,
 258		.bits_per_pixel = 32,
 259		.red	= { .length = 8, .offset = 24, .msb_right = 0 },
 260		.green	= { .length = 8, .offset = 16, .msb_right = 0 },
 261		.blue	= { .length = 8, .offset = 8, .msb_right = 0 },
 262		.transp	= { .length = 8, .offset = 0, .msb_right = 0 },
 263	}, {
 264		.dssmode = OMAP_DSS_COLOR_RGBX32,
 265		.bits_per_pixel = 32,
 266		.red	= { .length = 8, .offset = 24, .msb_right = 0 },
 267		.green	= { .length = 8, .offset = 16, .msb_right = 0 },
 268		.blue	= { .length = 8, .offset = 8, .msb_right = 0 },
 269		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
 270	},
 271};
 272
 273static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
 274		struct omapfb_colormode *color)
 275{
 276	bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
 277	{
 278		return f1->length == f2->length &&
 279			f1->offset == f2->offset &&
 280			f1->msb_right == f2->msb_right;
 281	}
 282
 283	if (var->bits_per_pixel == 0 ||
 284			var->red.length == 0 ||
 285			var->blue.length == 0 ||
 286			var->green.length == 0)
 287		return 0;
 288
 289	return var->bits_per_pixel == color->bits_per_pixel &&
 290		cmp_component(&var->red, &color->red) &&
 291		cmp_component(&var->green, &color->green) &&
 292		cmp_component(&var->blue, &color->blue) &&
 293		cmp_component(&var->transp, &color->transp);
 294}
 295
 296static void assign_colormode_to_var(struct fb_var_screeninfo *var,
 297		struct omapfb_colormode *color)
 298{
 299	var->bits_per_pixel = color->bits_per_pixel;
 300	var->nonstd = color->nonstd;
 301	var->red = color->red;
 302	var->green = color->green;
 303	var->blue = color->blue;
 304	var->transp = color->transp;
 305}
 306
 307int omapfb_mode_to_dss_mode(struct fb_var_screeninfo *var,
 308		enum omap_color_mode *mode)
 309{
 310	enum omap_color_mode dssmode;
 311	int i;
 312
 313	/* first match with nonstd field */
 314	if (var->nonstd) {
 315		for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
 316			struct omapfb_colormode *m = &omapfb_colormodes[i];
 317			if (var->nonstd == m->nonstd) {
 318				assign_colormode_to_var(var, m);
 319				*mode = m->dssmode;
 320				return 0;
 321			}
 322		}
 323
 324		return -EINVAL;
 325	}
 326
 327	/* then try exact match of bpp and colors */
 328	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
 329		struct omapfb_colormode *m = &omapfb_colormodes[i];
 330		if (cmp_var_to_colormode(var, m)) {
 331			assign_colormode_to_var(var, m);
 332			*mode = m->dssmode;
 333			return 0;
 334		}
 335	}
 336
 337	/* match with bpp if user has not filled color fields
 338	 * properly */
 339	switch (var->bits_per_pixel) {
 340	case 1:
 341		dssmode = OMAP_DSS_COLOR_CLUT1;
 342		break;
 343	case 2:
 344		dssmode = OMAP_DSS_COLOR_CLUT2;
 345		break;
 346	case 4:
 347		dssmode = OMAP_DSS_COLOR_CLUT4;
 348		break;
 349	case 8:
 350		dssmode = OMAP_DSS_COLOR_CLUT8;
 351		break;
 352	case 12:
 353		dssmode = OMAP_DSS_COLOR_RGB12U;
 354		break;
 355	case 16:
 356		dssmode = OMAP_DSS_COLOR_RGB16;
 357		break;
 358	case 24:
 359		dssmode = OMAP_DSS_COLOR_RGB24P;
 360		break;
 361	case 32:
 362		dssmode = OMAP_DSS_COLOR_ARGB32;
 363		break;
 364	default:
 365		return -EINVAL;
 366	}
 367
 368	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
 369		struct omapfb_colormode *m = &omapfb_colormodes[i];
 370		if (dssmode == m->dssmode) {
 371			assign_colormode_to_var(var, m);
 372			*mode = m->dssmode;
 373			return 0;
 374		}
 375	}
 376
 377	return -EINVAL;
 378}
 379EXPORT_SYMBOL(omapfb_mode_to_dss_mode);
 380
 381static int check_fb_res_bounds(struct fb_var_screeninfo *var)
 382{
 383	int xres_min = OMAPFB_PLANE_XRES_MIN;
 384	int xres_max = 2048;
 385	int yres_min = OMAPFB_PLANE_YRES_MIN;
 386	int yres_max = 2048;
 387
 388	/* XXX: some applications seem to set virtual res to 0. */
 389	if (var->xres_virtual == 0)
 390		var->xres_virtual = var->xres;
 391
 392	if (var->yres_virtual == 0)
 393		var->yres_virtual = var->yres;
 394
 395	if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
 396		return -EINVAL;
 397
 398	if (var->xres < xres_min)
 399		var->xres = xres_min;
 400	if (var->yres < yres_min)
 401		var->yres = yres_min;
 402	if (var->xres > xres_max)
 403		var->xres = xres_max;
 404	if (var->yres > yres_max)
 405		var->yres = yres_max;
 406
 407	if (var->xres > var->xres_virtual)
 408		var->xres = var->xres_virtual;
 409	if (var->yres > var->yres_virtual)
 410		var->yres = var->yres_virtual;
 411
 412	return 0;
 413}
 414
 415static void shrink_height(unsigned long max_frame_size,
 416		struct fb_var_screeninfo *var)
 417{
 418	DBG("can't fit FB into memory, reducing y\n");
 419	var->yres_virtual = max_frame_size /
 420		(var->xres_virtual * var->bits_per_pixel >> 3);
 421
 422	if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
 423		var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
 424
 425	if (var->yres > var->yres_virtual)
 426		var->yres = var->yres_virtual;
 427}
 428
 429static void shrink_width(unsigned long max_frame_size,
 430		struct fb_var_screeninfo *var)
 431{
 432	DBG("can't fit FB into memory, reducing x\n");
 433	var->xres_virtual = max_frame_size / var->yres_virtual /
 434		(var->bits_per_pixel >> 3);
 435
 436	if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
 437		var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
 438
 439	if (var->xres > var->xres_virtual)
 440		var->xres = var->xres_virtual;
 441}
 442
 443static int check_vrfb_fb_size(unsigned long region_size,
 444		const struct fb_var_screeninfo *var)
 445{
 446	unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
 447		var->yres_virtual, var->bits_per_pixel >> 3);
 448
 449	return min_phys_size > region_size ? -EINVAL : 0;
 450}
 451
 452static int check_fb_size(const struct omapfb_info *ofbi,
 453		struct fb_var_screeninfo *var)
 454{
 455	unsigned long max_frame_size = ofbi->region->size;
 456	int bytespp = var->bits_per_pixel >> 3;
 457	unsigned long line_size = var->xres_virtual * bytespp;
 458
 459	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
 460		/* One needs to check for both VRFB and OMAPFB limitations. */
 461		if (check_vrfb_fb_size(max_frame_size, var))
 462			shrink_height(omap_vrfb_max_height(
 463				max_frame_size, var->xres_virtual, bytespp) *
 464				line_size, var);
 465
 466		if (check_vrfb_fb_size(max_frame_size, var)) {
 467			DBG("cannot fit FB to memory\n");
 468			return -EINVAL;
 469		}
 470
 471		return 0;
 472	}
 473
 474	DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
 475
 476	if (line_size * var->yres_virtual > max_frame_size)
 477		shrink_height(max_frame_size, var);
 478
 479	if (line_size * var->yres_virtual > max_frame_size) {
 480		shrink_width(max_frame_size, var);
 481		line_size = var->xres_virtual * bytespp;
 482	}
 483
 484	if (line_size * var->yres_virtual > max_frame_size) {
 485		DBG("cannot fit FB to memory\n");
 486		return -EINVAL;
 487	}
 488
 489	return 0;
 490}
 491
 492/*
 493 * Consider if VRFB assisted rotation is in use and if the virtual space for
 494 * the zero degree view needs to be mapped. The need for mapping also acts as
 495 * the trigger for setting up the hardware on the context in question. This
 496 * ensures that one does not attempt to access the virtual view before the
 497 * hardware is serving the address translations.
 498 */
 499static int setup_vrfb_rotation(struct fb_info *fbi)
 500{
 501	struct omapfb_info *ofbi = FB2OFB(fbi);
 502	struct omapfb2_mem_region *rg = ofbi->region;
 503	struct vrfb *vrfb = &rg->vrfb;
 504	struct fb_var_screeninfo *var = &fbi->var;
 505	struct fb_fix_screeninfo *fix = &fbi->fix;
 506	unsigned bytespp;
 507	bool yuv_mode;
 508	enum omap_color_mode mode;
 509	int r;
 510	bool reconf;
 511
 512	if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
 513		return 0;
 514
 515	DBG("setup_vrfb_rotation\n");
 516
 517	r = omapfb_mode_to_dss_mode(var, &mode);
 518	if (r)
 519		return r;
 520
 521	bytespp = var->bits_per_pixel >> 3;
 522
 523	yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
 524
 525	/* We need to reconfigure VRFB if the resolution changes, if yuv mode
 526	 * is enabled/disabled, or if bytes per pixel changes */
 527
 528	/* XXX we shouldn't allow this when framebuffer is mmapped */
 529
 530	reconf = false;
 531
 532	if (yuv_mode != vrfb->yuv_mode)
 533		reconf = true;
 534	else if (bytespp != vrfb->bytespp)
 535		reconf = true;
 536	else if (vrfb->xres != var->xres_virtual ||
 537			vrfb->yres != var->yres_virtual)
 538		reconf = true;
 539
 540	if (vrfb->vaddr[0] && reconf) {
 541		fbi->screen_base = NULL;
 542		fix->smem_start = 0;
 543		fix->smem_len = 0;
 544		iounmap(vrfb->vaddr[0]);
 545		vrfb->vaddr[0] = NULL;
 546		DBG("setup_vrfb_rotation: reset fb\n");
 547	}
 548
 549	if (vrfb->vaddr[0])
 550		return 0;
 551
 552	omap_vrfb_setup(&rg->vrfb, rg->paddr,
 553			var->xres_virtual,
 554			var->yres_virtual,
 555			bytespp, yuv_mode);
 556
 557	/* Now one can ioremap the 0 angle view */
 558	r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
 559	if (r)
 560		return r;
 561
 562	/* used by open/write in fbmem.c */
 563	fbi->screen_base = ofbi->region->vrfb.vaddr[0];
 564
 565	fix->smem_start = ofbi->region->vrfb.paddr[0];
 566
 567	switch (var->nonstd) {
 568	case OMAPFB_COLOR_YUV422:
 569	case OMAPFB_COLOR_YUY422:
 570		fix->line_length =
 571			(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
 572		break;
 573	default:
 574		fix->line_length =
 575			(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
 576		break;
 577	}
 578
 579	fix->smem_len = var->yres_virtual * fix->line_length;
 580
 581	return 0;
 582}
 583
 584int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
 585			struct fb_var_screeninfo *var)
 586{
 587	int i;
 588
 589	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
 590		struct omapfb_colormode *mode = &omapfb_colormodes[i];
 591		if (dssmode == mode->dssmode) {
 592			assign_colormode_to_var(var, mode);
 593			return 0;
 594		}
 595	}
 596	return -ENOENT;
 597}
 598
 599void set_fb_fix(struct fb_info *fbi)
 600{
 601	struct fb_fix_screeninfo *fix = &fbi->fix;
 602	struct fb_var_screeninfo *var = &fbi->var;
 603	struct omapfb_info *ofbi = FB2OFB(fbi);
 604	struct omapfb2_mem_region *rg = ofbi->region;
 605
 606	DBG("set_fb_fix\n");
 607
 608	/* used by open/write in fbmem.c */
 609	fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
 610
 611	/* used by mmap in fbmem.c */
 612	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
 613		switch (var->nonstd) {
 614		case OMAPFB_COLOR_YUV422:
 615		case OMAPFB_COLOR_YUY422:
 616			fix->line_length =
 617				(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
 618			break;
 619		default:
 620			fix->line_length =
 621				(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
 622			break;
 623		}
 624
 625		fix->smem_len = var->yres_virtual * fix->line_length;
 626	} else {
 627		/* SGX requires stride to be a multiple of 32 pixels */
 628		int xres_align = ALIGN(var->xres_virtual, 32);
 629		fix->line_length = (xres_align * var->bits_per_pixel) >> 3;
 630		fix->smem_len = rg->size;
 631	}
 632
 633	fix->smem_start = omapfb_get_region_paddr(ofbi);
 634
 635	fix->type = FB_TYPE_PACKED_PIXELS;
 636
 637	if (var->nonstd)
 638		fix->visual = FB_VISUAL_PSEUDOCOLOR;
 639	else {
 640		switch (var->bits_per_pixel) {
 641		case 32:
 642		case 24:
 643		case 16:
 644		case 12:
 645			fix->visual = FB_VISUAL_TRUECOLOR;
 646			/* 12bpp is stored in 16 bits */
 647			break;
 648		case 1:
 649		case 2:
 650		case 4:
 651		case 8:
 652			fix->visual = FB_VISUAL_PSEUDOCOLOR;
 653			break;
 654		}
 655	}
 656
 657	fix->accel = FB_ACCEL_NONE;
 658
 659	fix->xpanstep = 1;
 660	fix->ypanstep = 1;
 661}
 662
 663/* check new var and possibly modify it to be ok */
 664int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
 665{
 666	struct omapfb_info *ofbi = FB2OFB(fbi);
 667	struct omap_dss_device *display = fb2display(fbi);
 668	enum omap_color_mode mode = 0;
 669	int i;
 670	int r;
 671	u32 w = 0, h = 0;
 672
 673	DBG("check_fb_var %d\n", ofbi->id);
 674
 675	WARN_ON(!atomic_read(&ofbi->region->lock_count));
 676
 677	r = omapfb_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)
 710		omapdss_display_get_dimensions(display, &w, &h);
 711
 712	if (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	struct omapfb_info *ofbi = FB2OFB(fbi);
 766	struct omapfb2_device *fbdev = ofbi->fbdev;
 767
 768	omapfb_disable_vsync(fbdev);
 769
 770	return 0;
 771}
 772
 773static unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var,
 774		const struct fb_fix_screeninfo *fix, int rotation)
 775{
 776	unsigned offset;
 777
 778	offset = var->yoffset * fix->line_length +
 779		var->xoffset * (var->bits_per_pixel >> 3);
 780
 781	return offset;
 782}
 783
 784static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
 785		const struct fb_fix_screeninfo *fix, int rotation)
 786{
 787	unsigned offset;
 788
 789	if (rotation == FB_ROTATE_UD)
 790		offset = (var->yres_virtual - var->yres) *
 791			fix->line_length;
 792	else if (rotation == FB_ROTATE_CW)
 793		offset = (var->yres_virtual - var->yres) *
 794			(var->bits_per_pixel >> 3);
 795	else
 796		offset = 0;
 797
 798	if (rotation == FB_ROTATE_UR)
 799		offset += var->yoffset * fix->line_length +
 800			var->xoffset * (var->bits_per_pixel >> 3);
 801	else if (rotation == FB_ROTATE_UD)
 802		offset -= var->yoffset * fix->line_length +
 803			var->xoffset * (var->bits_per_pixel >> 3);
 804	else if (rotation == FB_ROTATE_CW)
 805		offset -= var->xoffset * fix->line_length +
 806			var->yoffset * (var->bits_per_pixel >> 3);
 807	else if (rotation == FB_ROTATE_CCW)
 808		offset += var->xoffset * fix->line_length +
 809			var->yoffset * (var->bits_per_pixel >> 3);
 810
 811	return offset;
 812}
 813
 814static void omapfb_calc_addr(const struct omapfb_info *ofbi,
 815			     const struct fb_var_screeninfo *var,
 816			     const struct fb_fix_screeninfo *fix,
 817			     int rotation, u32 *paddr, void __iomem **vaddr)
 818{
 819	u32 data_start_p;
 820	void __iomem *data_start_v;
 821	int offset;
 822
 823	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
 824		data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
 825		data_start_v = NULL;
 826	} else {
 827		data_start_p = omapfb_get_region_paddr(ofbi);
 828		data_start_v = omapfb_get_region_vaddr(ofbi);
 829	}
 830
 831	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
 832		offset = calc_rotation_offset_vrfb(var, fix, rotation);
 833	else
 834		offset = calc_rotation_offset_dma(var, fix, rotation);
 835
 836	data_start_p += offset;
 837	data_start_v += offset;
 838
 839	if (offset)
 840		DBG("offset %d, %d = %d\n",
 841		    var->xoffset, var->yoffset, offset);
 842
 843	DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
 844
 845	*paddr = data_start_p;
 846	*vaddr = data_start_v;
 847}
 848
 849/* setup overlay according to the fb */
 850int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
 851		u16 posx, u16 posy, u16 outw, u16 outh)
 852{
 853	int r = 0;
 854	struct omapfb_info *ofbi = FB2OFB(fbi);
 855	struct fb_var_screeninfo *var = &fbi->var;
 856	struct fb_fix_screeninfo *fix = &fbi->fix;
 857	enum omap_color_mode mode = 0;
 858	u32 data_start_p = 0;
 859	void __iomem *data_start_v = NULL;
 860	struct omap_overlay_info info;
 861	int xres, yres;
 862	int screen_width;
 863	int mirror;
 864	int rotation = var->rotate;
 865	int i;
 866
 867	WARN_ON(!atomic_read(&ofbi->region->lock_count));
 868
 869	for (i = 0; i < ofbi->num_overlays; i++) {
 870		if (ovl != ofbi->overlays[i])
 871			continue;
 872
 873		rotation = (rotation + ofbi->rotation[i]) % 4;
 874		break;
 875	}
 876
 877	DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
 878			posx, posy, outw, outh);
 879
 880	if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
 881		xres = var->yres;
 882		yres = var->xres;
 883	} else {
 884		xres = var->xres;
 885		yres = var->yres;
 886	}
 887
 888	if (ofbi->region->size)
 889		omapfb_calc_addr(ofbi, var, fix, rotation,
 890				 &data_start_p, &data_start_v);
 891
 892	r = omapfb_mode_to_dss_mode(var, &mode);
 893	if (r) {
 894		DBG("omapfb_mode_to_dss_mode failed");
 895		goto err;
 896	}
 897
 898	switch (var->nonstd) {
 899	case OMAPFB_COLOR_YUV422:
 900	case OMAPFB_COLOR_YUY422:
 901		if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
 902			screen_width = fix->line_length
 903				/ (var->bits_per_pixel >> 2);
 904			break;
 905		}
 906	default:
 907		screen_width = fix->line_length / (var->bits_per_pixel >> 3);
 908		break;
 909	}
 910
 911	ovl->get_overlay_info(ovl, &info);
 912
 913	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
 914		mirror = 0;
 915	else
 916		mirror = ofbi->mirror;
 917
 918	info.paddr = data_start_p;
 919	info.vaddr = data_start_v;
 920	info.screen_width = screen_width;
 921	info.width = xres;
 922	info.height = yres;
 923	info.color_mode = mode;
 924	info.rotation_type = ofbi->rotation_type;
 925	info.rotation = rotation;
 926	info.mirror = mirror;
 927
 928	info.pos_x = posx;
 929	info.pos_y = posy;
 930	info.out_width = outw;
 931	info.out_height = outh;
 932
 933	r = ovl->set_overlay_info(ovl, &info);
 934	if (r) {
 935		DBG("ovl->setup_overlay_info failed\n");
 936		goto err;
 937	}
 938
 939	return 0;
 940
 941err:
 942	DBG("setup_overlay failed\n");
 943	return r;
 944}
 945
 946/* apply var to the overlay */
 947int omapfb_apply_changes(struct fb_info *fbi, int init)
 948{
 949	int r = 0;
 950	struct omapfb_info *ofbi = FB2OFB(fbi);
 951	struct fb_var_screeninfo *var = &fbi->var;
 952	struct omap_overlay *ovl;
 953	u16 posx, posy;
 954	u16 outw, outh;
 955	int i;
 956
 957#ifdef DEBUG
 958	if (omapfb_test_pattern)
 959		fill_fb(fbi);
 960#endif
 961
 962	WARN_ON(!atomic_read(&ofbi->region->lock_count));
 963
 964	for (i = 0; i < ofbi->num_overlays; i++) {
 965		ovl = ofbi->overlays[i];
 966
 967		DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
 968
 969		if (ofbi->region->size == 0) {
 970			/* the fb is not available. disable the overlay */
 971			omapfb_overlay_enable(ovl, 0);
 972			if (!init && ovl->manager)
 973				ovl->manager->apply(ovl->manager);
 974			continue;
 975		}
 976
 977		if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
 978			int rotation = (var->rotate + ofbi->rotation[i]) % 4;
 979			if (rotation == FB_ROTATE_CW ||
 980					rotation == FB_ROTATE_CCW) {
 981				outw = var->yres;
 982				outh = var->xres;
 983			} else {
 984				outw = var->xres;
 985				outh = var->yres;
 986			}
 987		} else {
 988			outw = ovl->info.out_width;
 989			outh = ovl->info.out_height;
 990		}
 991
 992		if (init) {
 993			posx = 0;
 994			posy = 0;
 995		} else {
 996			posx = ovl->info.pos_x;
 997			posy = ovl->info.pos_y;
 998		}
 999
1000		r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
1001		if (r)
1002			goto err;
1003
1004		if (!init && ovl->manager)
1005			ovl->manager->apply(ovl->manager);
1006	}
1007	return 0;
1008err:
1009	DBG("apply_changes failed\n");
1010	return r;
1011}
1012
1013/* checks var and eventually tweaks it to something supported,
1014 * DO NOT MODIFY PAR */
1015static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
1016{
1017	struct omapfb_info *ofbi = FB2OFB(fbi);
1018	int r;
1019
1020	DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1021
1022	omapfb_get_mem_region(ofbi->region);
1023
1024	r = check_fb_var(fbi, var);
1025
1026	omapfb_put_mem_region(ofbi->region);
1027
1028	return r;
1029}
1030
1031void omapfb_fb2dss_timings(struct fb_videomode *fb_timings,
1032			struct omap_video_timings *dss_timings)
1033{
1034	dss_timings->x_res = fb_timings->xres;
1035	dss_timings->y_res = fb_timings->yres;
1036	if (fb_timings->vmode & FB_VMODE_INTERLACED)
1037		dss_timings->y_res /= 2;
1038	dss_timings->pixel_clock = fb_timings->pixclock ?
1039					PICOS2KHZ(fb_timings->pixclock) : 0;
1040	dss_timings->hfp = fb_timings->right_margin;
1041	dss_timings->hbp = fb_timings->left_margin;
1042	dss_timings->hsw = fb_timings->hsync_len;
1043	dss_timings->vfp = fb_timings->lower_margin;
1044	dss_timings->vbp = fb_timings->upper_margin;
1045	dss_timings->vsw = fb_timings->vsync_len;
1046}
1047EXPORT_SYMBOL(omapfb_fb2dss_timings);
1048
1049void omapfb_dss2fb_timings(struct omap_video_timings *dss_timings,
1050			struct fb_videomode *fb_timings)
1051{
1052	memset(fb_timings, 0, sizeof(*fb_timings));
1053	fb_timings->xres = dss_timings->x_res;
1054	fb_timings->yres = dss_timings->y_res;
1055	fb_timings->pixclock = dss_timings->pixel_clock ?
1056					KHZ2PICOS(dss_timings->pixel_clock) : 0;
1057	fb_timings->right_margin = dss_timings->hfp;
1058	fb_timings->left_margin = dss_timings->hbp;
1059	fb_timings->hsync_len = dss_timings->hsw;
1060	fb_timings->lower_margin = dss_timings->vfp;
1061	fb_timings->upper_margin = dss_timings->vbp;
1062	fb_timings->vsync_len = dss_timings->vsw;
1063}
1064EXPORT_SYMBOL(omapfb_dss2fb_timings);
1065
1066/* set the video mode according to info->var */
1067static int omapfb_set_par(struct fb_info *fbi)
1068{
1069	struct omapfb_info *ofbi = FB2OFB(fbi);
1070	int r;
1071
1072	DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1073
1074	omapfb_get_mem_region(ofbi->region);
1075
1076	set_fb_fix(fbi);
1077
1078	r = setup_vrfb_rotation(fbi);
1079	if (r)
1080		goto out;
1081
1082	r = omapfb_apply_changes(fbi, 0);
1083
1084 out:
1085	omapfb_put_mem_region(ofbi->region);
1086
1087	return r;
1088}
1089
1090static int omapfb_pan_display(struct fb_var_screeninfo *var,
1091		struct fb_info *fbi)
1092{
1093	struct omapfb_info *ofbi = FB2OFB(fbi);
1094	struct fb_var_screeninfo new_var;
1095	int r;
1096
1097	DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
1098
1099	if (var->xoffset == fbi->var.xoffset &&
1100	    var->yoffset == fbi->var.yoffset)
1101		return 0;
1102
1103	new_var = fbi->var;
1104	new_var.xoffset = var->xoffset;
1105	new_var.yoffset = var->yoffset;
1106
1107	fbi->var = new_var;
1108
1109	omapfb_get_mem_region(ofbi->region);
1110
1111	r = omapfb_apply_changes(fbi, 0);
1112
1113	omapfb_put_mem_region(ofbi->region);
1114
1115	return r;
1116}
1117
1118static void mmap_user_open(struct vm_area_struct *vma)
1119{
1120	struct omapfb2_mem_region *rg = vma->vm_private_data;
1121
1122	omapfb_get_mem_region(rg);
1123	atomic_inc(&rg->map_count);
1124	omapfb_put_mem_region(rg);
1125}
1126
1127static void mmap_user_close(struct vm_area_struct *vma)
1128{
1129	struct omapfb2_mem_region *rg = vma->vm_private_data;
1130
1131	omapfb_get_mem_region(rg);
1132	atomic_dec(&rg->map_count);
1133	omapfb_put_mem_region(rg);
1134}
1135
1136static struct vm_operations_struct mmap_user_ops = {
1137	.open = mmap_user_open,
1138	.close = mmap_user_close,
1139};
1140
1141static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1142{
1143	struct omapfb_info *ofbi = FB2OFB(fbi);
1144	struct fb_fix_screeninfo *fix = &fbi->fix;
1145	struct omapfb2_mem_region *rg;
1146	unsigned long off;
1147	unsigned long start;
1148	u32 len;
1149	int r = -EINVAL;
1150
1151	if (vma->vm_end - vma->vm_start == 0)
1152		return 0;
1153	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1154		return -EINVAL;
1155	off = vma->vm_pgoff << PAGE_SHIFT;
1156
1157	rg = omapfb_get_mem_region(ofbi->region);
1158
1159	start = omapfb_get_region_paddr(ofbi);
1160	len = fix->smem_len;
1161	if (off >= len)
1162		goto error;
1163	if ((vma->vm_end - vma->vm_start + off) > len)
1164		goto error;
1165
1166	off += start;
1167
1168	DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
1169
1170	vma->vm_pgoff = off >> PAGE_SHIFT;
1171	vma->vm_flags |= VM_IO | VM_RESERVED;
1172	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1173	vma->vm_ops = &mmap_user_ops;
1174	vma->vm_private_data = rg;
1175	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1176			       vma->vm_end - vma->vm_start,
1177			       vma->vm_page_prot)) {
1178		r = -EAGAIN;
1179		goto error;
1180	}
1181
1182	/* vm_ops.open won't be called for mmap itself. */
1183	atomic_inc(&rg->map_count);
1184
1185	omapfb_put_mem_region(rg);
1186
1187	return 0;
1188
1189 error:
1190	omapfb_put_mem_region(ofbi->region);
1191
1192	return r;
1193}
1194
1195/* Store a single color palette entry into a pseudo palette or the hardware
1196 * palette if one is available. For now we support only 16bpp and thus store
1197 * the entry only to the pseudo palette.
1198 */
1199static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1200		u_int blue, u_int transp, int update_hw_pal)
1201{
1202	/*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1203	/*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1204	struct fb_var_screeninfo *var = &fbi->var;
1205	int r = 0;
1206
1207	enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1208
1209	/*switch (plane->color_mode) {*/
1210	switch (mode) {
1211	case OMAPFB_COLOR_YUV422:
1212	case OMAPFB_COLOR_YUV420:
1213	case OMAPFB_COLOR_YUY422:
1214		r = -EINVAL;
1215		break;
1216	case OMAPFB_COLOR_CLUT_8BPP:
1217	case OMAPFB_COLOR_CLUT_4BPP:
1218	case OMAPFB_COLOR_CLUT_2BPP:
1219	case OMAPFB_COLOR_CLUT_1BPP:
1220		/*
1221		   if (fbdev->ctrl->setcolreg)
1222		   r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1223		   transp, update_hw_pal);
1224		   */
1225		/* Fallthrough */
1226		r = -EINVAL;
1227		break;
1228	case OMAPFB_COLOR_RGB565:
1229	case OMAPFB_COLOR_RGB444:
1230	case OMAPFB_COLOR_RGB24P:
1231	case OMAPFB_COLOR_RGB24U:
1232		if (r != 0)
1233			break;
1234
1235		if (regno < 16) {
1236			u16 pal;
1237			pal = ((red >> (16 - var->red.length)) <<
1238					var->red.offset) |
1239				((green >> (16 - var->green.length)) <<
1240				 var->green.offset) |
1241				(blue >> (16 - var->blue.length));
1242			((u32 *)(fbi->pseudo_palette))[regno] = pal;
1243		}
1244		break;
1245	default:
1246		BUG();
1247	}
1248	return r;
1249}
1250
1251static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1252		u_int transp, struct fb_info *info)
1253{
1254	DBG("setcolreg\n");
1255
1256	return _setcolreg(info, regno, red, green, blue, transp, 1);
1257}
1258
1259static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1260{
1261	int count, index, r;
1262	u16 *red, *green, *blue, *transp;
1263	u16 trans = 0xffff;
1264
1265	DBG("setcmap\n");
1266
1267	red     = cmap->red;
1268	green   = cmap->green;
1269	blue    = cmap->blue;
1270	transp  = cmap->transp;
1271	index   = cmap->start;
1272
1273	for (count = 0; count < cmap->len; count++) {
1274		if (transp)
1275			trans = *transp++;
1276		r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1277				count == cmap->len - 1);
1278		if (r != 0)
1279			return r;
1280	}
1281
1282	return 0;
1283}
1284
1285static int omapfb_blank(int blank, struct fb_info *fbi)
1286{
1287	struct omapfb_info *ofbi = FB2OFB(fbi);
1288	struct omapfb2_device *fbdev = ofbi->fbdev;
1289	struct omap_dss_device *display = fb2display(fbi);
1290	int r = 0;
1291
1292	if (!display)
1293		return -EINVAL;
1294
1295	omapfb_lock(fbdev);
1296
1297	switch (blank) {
1298	case FB_BLANK_UNBLANK:
1299		if (display->state == OMAP_DSS_DISPLAY_SUSPENDED) {
1300			if (display->driver->resume)
1301				r = display->driver->resume(display);
1302		} else if (display->state == OMAP_DSS_DISPLAY_DISABLED) {
1303			if (display->driver->enable)
1304				r = display->driver->enable(display);
1305		}
1306
1307		if (fbdev->vsync_active)
1308			omapfb_enable_vsync(fbdev);
1309
1310		break;
1311
1312	case FB_BLANK_NORMAL:
1313		/* FB_BLANK_NORMAL could be implemented.
1314		 * Needs DSS additions. */
1315	case FB_BLANK_VSYNC_SUSPEND:
1316	case FB_BLANK_HSYNC_SUSPEND:
1317	case FB_BLANK_POWERDOWN:
1318
1319		if (fbdev->vsync_active)
1320			omapfb_disable_vsync(fbdev);
1321
1322		if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1323			goto exit;
1324
1325		if (display->driver->suspend)
1326			r = display->driver->suspend(display);
1327		else if (display->driver->disable)
1328			display->driver->disable(display);
1329
1330		break;
1331
1332	default:
1333		r = -EINVAL;
1334	}
1335
1336exit:
1337	omapfb_unlock(fbdev);
1338
1339	return r;
1340}
1341
1342#if 0
1343/* XXX fb_read and fb_write are needed for VRFB */
1344ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1345		size_t count, loff_t *ppos)
1346{
1347	DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1348	/* XXX needed for VRFB */
1349	return count;
1350}
1351#endif
1352
1353static struct fb_ops omapfb_ops = {
1354	.owner          = THIS_MODULE,
1355	.fb_open        = omapfb_open,
1356	.fb_release     = omapfb_release,
1357	.fb_fillrect    = cfb_fillrect,
1358	.fb_copyarea    = cfb_copyarea,
1359	.fb_imageblit   = cfb_imageblit,
1360	.fb_blank       = omapfb_blank,
1361	.fb_ioctl       = omapfb_ioctl,
1362	.fb_check_var   = omapfb_check_var,
1363	.fb_set_par     = omapfb_set_par,
1364	.fb_pan_display = omapfb_pan_display,
1365	.fb_mmap	= omapfb_mmap,
1366	.fb_setcolreg	= omapfb_setcolreg,
1367	.fb_setcmap	= omapfb_setcmap,
1368	/*.fb_write	= omapfb_write,*/
1369};
1370
1371static void omapfb_free_fbmem(struct fb_info *fbi)
1372{
1373	struct omapfb_info *ofbi = FB2OFB(fbi);
1374	struct omapfb2_device *fbdev = ofbi->fbdev;
1375	struct omapfb2_mem_region *rg;
1376
1377	rg = ofbi->region;
1378
1379	WARN_ON(atomic_read(&rg->map_count));
1380
1381	if (rg->paddr)
1382		if (omap_vram_free(rg->paddr, rg->size))
1383			dev_err(fbdev->dev, "VRAM FREE failed\n");
1384
1385	if (rg->vaddr)
1386		iounmap(rg->vaddr);
1387
1388	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1389		/* unmap the 0 angle rotation */
1390		if (rg->vrfb.vaddr[0]) {
1391			iounmap(rg->vrfb.vaddr[0]);
1392			omap_vrfb_release_ctx(&rg->vrfb);
1393			rg->vrfb.vaddr[0] = NULL;
1394		}
1395	}
1396
1397	rg->vaddr = NULL;
1398	rg->paddr = 0;
1399	rg->alloc = 0;
1400	rg->size = 0;
1401}
1402
1403static void clear_fb_info(struct fb_info *fbi)
1404{
1405	memset(&fbi->var, 0, sizeof(fbi->var));
1406	memset(&fbi->fix, 0, sizeof(fbi->fix));
1407	strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1408}
1409
1410static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1411{
1412	int i;
1413
1414	DBG("free all fbmem\n");
1415
1416	for (i = 0; i < fbdev->num_fbs; i++) {
1417		struct fb_info *fbi = fbdev->fbs[i];
1418		omapfb_free_fbmem(fbi);
1419		clear_fb_info(fbi);
1420	}
1421
1422	return 0;
1423}
1424
1425static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1426		unsigned long paddr)
1427{
1428	struct omapfb_info *ofbi = FB2OFB(fbi);
1429	struct omapfb2_device *fbdev = ofbi->fbdev;
1430	struct omapfb2_mem_region *rg;
1431	void __iomem *vaddr;
1432	int r;
1433
1434	rg = ofbi->region;
1435
1436	rg->paddr = 0;
1437	rg->vaddr = NULL;
1438	memset(&rg->vrfb, 0, sizeof rg->vrfb);
1439	rg->size = 0;
1440	rg->type = 0;
1441	rg->alloc = false;
1442	rg->map = false;
1443
1444	size = PAGE_ALIGN(size);
1445
1446	if (!paddr) {
1447		DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1448		r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
1449	} else {
1450		DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1451				ofbi->id);
1452		r = omap_vram_reserve(paddr, size);
1453	}
1454
1455	if (r) {
1456		dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1457		return -ENOMEM;
1458	}
1459
1460	if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
1461		vaddr = ioremap_wc(paddr, size);
1462
1463		if (!vaddr) {
1464			dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1465			omap_vram_free(paddr, size);
1466			return -ENOMEM;
1467		}
1468
1469		DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1470	} else {
1471		r = omap_vrfb_request_ctx(&rg->vrfb);
1472		if (r) {
1473			dev_err(fbdev->dev, "vrfb create ctx failed\n");
1474			return r;
1475		}
1476
1477		vaddr = NULL;
1478	}
1479
1480	rg->paddr = paddr;
1481	rg->vaddr = vaddr;
1482	rg->size = size;
1483	rg->alloc = 1;
1484
1485	return 0;
1486}
1487
1488/* allocate fbmem using display resolution as reference */
1489static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1490		unsigned long paddr)
1491{
1492	struct omapfb_info *ofbi = FB2OFB(fbi);
1493	struct omapfb2_device *fbdev = ofbi->fbdev;
1494	struct omap_dss_device *display;
1495	int bytespp;
1496
1497	display =  fb2display(fbi);
1498
1499	if (!display)
1500		return 0;
1501
1502	switch (omapfb_get_recommended_bpp(fbdev, display)) {
1503	case 16:
1504		bytespp = 2;
1505		break;
1506	case 24:
1507		bytespp = 4;
1508		break;
1509	default:
1510		bytespp = 4;
1511		break;
1512	}
1513
1514	if (!size) {
1515		u16 w, h;
1516
1517		display->driver->get_resolution(display, &w, &h);
1518
1519		if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1520			size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1521					omap_vrfb_min_phys_size(h, w, bytespp));
1522
1523			DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1524					w * h * bytespp, size);
1525		} else {
1526			size = w * h * bytespp;
1527		}
1528	}
1529
1530	if (!size)
1531		return 0;
1532
1533	return omapfb_alloc_fbmem(fbi, size, paddr);
1534}
1535
1536static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
1537{
1538	enum omap_color_mode mode;
1539
1540	switch (fmt) {
1541	case OMAPFB_COLOR_RGB565:
1542		mode = OMAP_DSS_COLOR_RGB16;
1543		break;
1544	case OMAPFB_COLOR_YUV422:
1545		mode = OMAP_DSS_COLOR_YUV2;
1546		break;
1547	case OMAPFB_COLOR_CLUT_8BPP:
1548		mode = OMAP_DSS_COLOR_CLUT8;
1549		break;
1550	case OMAPFB_COLOR_CLUT_4BPP:
1551		mode = OMAP_DSS_COLOR_CLUT4;
1552		break;
1553	case OMAPFB_COLOR_CLUT_2BPP:
1554		mode = OMAP_DSS_COLOR_CLUT2;
1555		break;
1556	case OMAPFB_COLOR_CLUT_1BPP:
1557		mode = OMAP_DSS_COLOR_CLUT1;
1558		break;
1559	case OMAPFB_COLOR_RGB444:
1560		mode = OMAP_DSS_COLOR_RGB12U;
1561		break;
1562	case OMAPFB_COLOR_YUY422:
1563		mode = OMAP_DSS_COLOR_UYVY;
1564		break;
1565	case OMAPFB_COLOR_ARGB16:
1566		mode = OMAP_DSS_COLOR_ARGB16;
1567		break;
1568	case OMAPFB_COLOR_RGB24U:
1569		mode = OMAP_DSS_COLOR_RGB24U;
1570		break;
1571	case OMAPFB_COLOR_RGB24P:
1572		mode = OMAP_DSS_COLOR_RGB24P;
1573		break;
1574	case OMAPFB_COLOR_ARGB32:
1575		mode = OMAP_DSS_COLOR_ARGB32;
1576		break;
1577	case OMAPFB_COLOR_RGBA32:
1578		mode = OMAP_DSS_COLOR_RGBA32;
1579		break;
1580	case OMAPFB_COLOR_RGBX32:
1581		mode = OMAP_DSS_COLOR_RGBX32;
1582		break;
1583	default:
1584		mode = -EINVAL;
1585	}
1586
1587	return mode;
1588}
1589
1590static int omapfb_parse_vram_param(const char *param, int max_entries,
1591		unsigned long *sizes, unsigned long *paddrs)
1592{
1593	int fbnum;
1594	unsigned long size;
1595	unsigned long paddr = 0;
1596	char *p, *start;
1597
1598	start = (char *)param;
1599
1600	while (1) {
1601		p = start;
1602
1603		fbnum = simple_strtoul(p, &p, 10);
1604
1605		if (p == param)
1606			return -EINVAL;
1607
1608		if (*p != ':')
1609			return -EINVAL;
1610
1611		if (fbnum >= max_entries)
1612			return -EINVAL;
1613
1614		size = memparse(p + 1, &p);
1615
1616		if (!size)
1617			return -EINVAL;
1618
1619		paddr = 0;
1620
1621		if (*p == '@') {
1622			paddr = simple_strtoul(p + 1, &p, 16);
1623
1624			if (!paddr)
1625				return -EINVAL;
1626
1627		}
1628
1629		paddrs[fbnum] = paddr;
1630		sizes[fbnum] = size;
1631
1632		if (*p == 0)
1633			break;
1634
1635		if (*p != ',')
1636			return -EINVAL;
1637
1638		++p;
1639
1640		start = p;
1641	}
1642
1643	return 0;
1644}
1645
1646static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1647{
1648	int i, r;
1649	unsigned long vram_sizes[10];
1650	unsigned long vram_paddrs[10];
1651
1652	memset(&vram_sizes, 0, sizeof(vram_sizes));
1653	memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1654
1655	if (def_vram &&	omapfb_parse_vram_param(def_vram, 10,
1656				vram_sizes, vram_paddrs)) {
1657		dev_err(fbdev->dev, "failed to parse vram parameter\n");
1658
1659		memset(&vram_sizes, 0, sizeof(vram_sizes));
1660		memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1661	}
1662
1663	if (fbdev->dev->platform_data) {
1664		struct omapfb_platform_data *opd;
1665		opd = fbdev->dev->platform_data;
1666		for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
1667			if (!vram_sizes[i]) {
1668				unsigned long size;
1669				unsigned long paddr;
1670
1671				size = opd->mem_desc.region[i].size;
1672				paddr = opd->mem_desc.region[i].paddr;
1673
1674				vram_sizes[i] = size;
1675				vram_paddrs[i] = paddr;
1676			}
1677		}
1678	}
1679
1680	for (i = 0; i < fbdev->num_fbs; i++) {
1681		/* allocate memory automatically only for fb0, or if
1682		 * excplicitly defined with vram or plat data option */
1683		if (i == 0 || vram_sizes[i] != 0) {
1684			r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1685					vram_sizes[i], vram_paddrs[i]);
1686
1687			if (r)
1688				return r;
1689		}
1690	}
1691
1692	for (i = 0; i < fbdev->num_fbs; i++) {
1693		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1694		struct omapfb2_mem_region *rg;
1695		rg = ofbi->region;
1696
1697		DBG("region%d phys %08x virt %p size=%lu\n",
1698				i,
1699				rg->paddr,
1700				rg->vaddr,
1701				rg->size);
1702	}
1703
1704	return 0;
1705}
1706
1707int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1708{
1709	struct omapfb_info *ofbi = FB2OFB(fbi);
1710	struct omapfb2_device *fbdev = ofbi->fbdev;
1711	struct omap_dss_device *display = fb2display(fbi);
1712	struct omapfb2_mem_region *rg = ofbi->region;
1713	unsigned long old_size = rg->size;
1714	unsigned long old_paddr = rg->paddr;
1715	int old_type = rg->type;
1716	int r;
1717
1718	if (type > OMAPFB_MEMTYPE_MAX)
1719		return -EINVAL;
1720
1721	size = PAGE_ALIGN(size);
1722
1723	if (old_size == size && old_type == type)
1724		return 0;
1725
1726	if (display && display->driver->sync)
1727			display->driver->sync(display);
1728
1729	omapfb_free_fbmem(fbi);
1730
1731	if (size == 0) {
1732		clear_fb_info(fbi);
1733		return 0;
1734	}
1735
1736	r = omapfb_alloc_fbmem(fbi, size, 0);
1737
1738	if (r) {
1739		if (old_size)
1740			omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1741
1742		if (rg->size == 0)
1743			clear_fb_info(fbi);
1744
1745		return r;
1746	}
1747
1748	if (old_size == size)
1749		return 0;
1750
1751	if (old_size == 0) {
1752		DBG("initializing fb %d\n", ofbi->id);
1753		r = omapfb_fb_init(fbdev, fbi);
1754		if (r) {
1755			DBG("omapfb_fb_init failed\n");
1756			goto err;
1757		}
1758		r = omapfb_apply_changes(fbi, 1);
1759		if (r) {
1760			DBG("omapfb_apply_changes failed\n");
1761			goto err;
1762		}
1763	} else {
1764		struct fb_var_screeninfo new_var;
1765		memcpy(&new_var, &fbi->var, sizeof(new_var));
1766		r = check_fb_var(fbi, &new_var);
1767		if (r)
1768			goto err;
1769		memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1770		set_fb_fix(fbi);
1771		r = setup_vrfb_rotation(fbi);
1772		if (r)
1773			goto err;
1774	}
1775
1776	return 0;
1777err:
1778	omapfb_free_fbmem(fbi);
1779	clear_fb_info(fbi);
1780	return r;
1781}
1782
1783/* initialize fb_info, var, fix to something sane based on the display */
1784static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1785{
1786	struct fb_var_screeninfo *var = &fbi->var;
1787	struct omap_dss_device *display = fb2display(fbi);
1788	struct omapfb_info *ofbi = FB2OFB(fbi);
1789	int r = 0;
1790
1791	fbi->fbops = &omapfb_ops;
1792	fbi->flags = FBINFO_FLAG_DEFAULT;
1793	fbi->pseudo_palette = fbdev->pseudo_palette;
1794
1795	if (ofbi->region->size == 0) {
1796		clear_fb_info(fbi);
1797		return 0;
1798	}
1799
1800	var->nonstd = 0;
1801	var->bits_per_pixel = 0;
1802
1803	var->rotate = def_rotate;
1804
1805	/*
1806	 * Check if there is a default color format set in the board file,
1807	 * and use this format instead the default deducted from the
1808	 * display bpp.
1809	 */
1810	if (fbdev->dev->platform_data) {
1811		struct omapfb_platform_data *opd;
1812		int id = ofbi->id;
1813
1814		opd = fbdev->dev->platform_data;
1815		if (opd->mem_desc.region[id].format_used) {
1816			enum omap_color_mode mode;
1817			enum omapfb_color_format format;
1818
1819			format = opd->mem_desc.region[id].format;
1820			mode = fb_format_to_dss_mode(format);
1821			if (mode < 0) {
1822				r = mode;
1823				goto err;
1824			}
1825			r = dss_mode_to_fb_mode(mode, var);
1826			if (r < 0)
1827				goto err;
1828		}
1829	}
1830
1831	if (display) {
1832		u16 w, h;
1833		int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1834
1835		display->driver->get_resolution(display, &w, &h);
1836
1837		if (rotation == FB_ROTATE_CW ||
1838				rotation == FB_ROTATE_CCW) {
1839			var->xres = h;
1840			var->yres = w;
1841		} else {
1842			var->xres = w;
1843			var->yres = h;
1844		}
1845
1846		var->xres_virtual = var->xres;
1847		var->yres_virtual = var->yres;
1848
1849		if (!var->bits_per_pixel) {
1850			switch (omapfb_get_recommended_bpp(fbdev, display)) {
1851			case 16:
1852				var->bits_per_pixel = 16;
1853				break;
1854			case 24:
1855				var->bits_per_pixel = 32;
1856				break;
1857			default:
1858				dev_err(fbdev->dev, "illegal display "
1859						"bpp\n");
1860				return -EINVAL;
1861			}
1862		}
1863	} else {
1864		/* if there's no display, let's just guess some basic values */
1865		var->xres = 320;
1866		var->yres = 240;
1867		var->xres_virtual = var->xres;
1868		var->yres_virtual = var->yres;
1869		if (!var->bits_per_pixel)
1870			var->bits_per_pixel = 16;
1871	}
1872
1873	r = check_fb_var(fbi, var);
1874	if (r)
1875		goto err;
1876
1877	set_fb_fix(fbi);
1878	r = setup_vrfb_rotation(fbi);
1879	if (r)
1880		goto err;
1881
1882	r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1883	if (r)
1884		dev_err(fbdev->dev, "unable to allocate color map memory\n");
1885
1886err:
1887	return r;
1888}
1889
1890static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1891{
1892	fb_dealloc_cmap(&fbi->cmap);
1893}
1894
1895
1896static void omapfb_free_resources(struct omapfb2_device *fbdev)
1897{
1898	int i;
1899
1900	DBG("free_resources\n");
1901
1902	if (fbdev == NULL)
1903		return;
1904
1905	for (i = 0; i < fbdev->num_fbs; i++)
1906		unregister_framebuffer(fbdev->fbs[i]);
1907
1908	/* free the reserved fbmem */
1909	omapfb_free_all_fbmem(fbdev);
1910
1911	for (i = 0; i < fbdev->num_fbs; i++) {
1912		fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1913		framebuffer_release(fbdev->fbs[i]);
1914	}
1915
1916	for (i = 0; i < fbdev->num_displays; i++) {
1917		if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
1918			fbdev->displays[i]->driver->disable(fbdev->displays[i]);
1919
1920		omap_dss_put_device(fbdev->displays[i]);
1921	}
1922
1923	dev_set_drvdata(fbdev->dev, NULL);
1924	kfree(fbdev);
1925}
1926
1927static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1928{
1929	int r, i;
1930
1931	fbdev->num_fbs = 0;
1932
1933	DBG("create %d framebuffers\n",	CONFIG_FB_OMAP2_NUM_FBS);
1934
1935	/* allocate fb_infos */
1936	for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1937		struct fb_info *fbi;
1938		struct omapfb_info *ofbi;
1939
1940		fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1941				fbdev->dev);
1942
1943		if (fbi == NULL) {
1944			dev_err(fbdev->dev,
1945				"unable to allocate memory for plane info\n");
1946			return -ENOMEM;
1947		}
1948
1949		clear_fb_info(fbi);
1950
1951		fbdev->fbs[i] = fbi;
1952
1953		ofbi = FB2OFB(fbi);
1954		ofbi->fbdev = fbdev;
1955		ofbi->id = i;
1956
1957		ofbi->region = &fbdev->regions[i];
1958		ofbi->region->id = i;
1959		init_rwsem(&ofbi->region->lock);
1960
1961		/* assign these early, so that fb alloc can use them */
1962		ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1963			OMAP_DSS_ROT_DMA;
1964		ofbi->mirror = def_mirror;
1965
1966		fbdev->num_fbs++;
1967	}
1968
1969	DBG("fb_infos allocated\n");
1970
1971	/* assign overlays for the fbs */
1972	for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1973		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1974
1975		ofbi->overlays[0] = fbdev->overlays[i];
1976		ofbi->num_overlays = 1;
1977	}
1978
1979	/* allocate fb memories */
1980	r = omapfb_allocate_all_fbs(fbdev);
1981	if (r) {
1982		dev_err(fbdev->dev, "failed to allocate fbmem\n");
1983		return r;
1984	}
1985
1986	DBG("fbmems allocated\n");
1987
1988	/* setup fb_infos */
1989	for (i = 0; i < fbdev->num_fbs; i++) {
1990		struct fb_info *fbi = fbdev->fbs[i];
1991		struct omapfb_info *ofbi = FB2OFB(fbi);
1992
1993		omapfb_get_mem_region(ofbi->region);
1994		r = omapfb_fb_init(fbdev, fbi);
1995		omapfb_put_mem_region(ofbi->region);
1996
1997		if (r) {
1998			dev_err(fbdev->dev, "failed to setup fb_info\n");
1999			return r;
2000		}
2001	}
2002
2003	DBG("fb_infos initialized\n");
2004
2005	for (i = 0; i < fbdev->num_fbs; i++) {
2006		r = register_framebuffer(fbdev->fbs[i]);
2007		if (r != 0) {
2008			dev_err(fbdev->dev,
2009				"registering framebuffer %d failed\n", i);
2010			return r;
2011		}
2012	}
2013
2014	DBG("framebuffers registered\n");
2015
2016	for (i = 0; i < fbdev->num_fbs; i++) {
2017		struct fb_info *fbi = fbdev->fbs[i];
2018		struct omapfb_info *ofbi = FB2OFB(fbi);
2019
2020		omapfb_get_mem_region(ofbi->region);
2021		r = omapfb_apply_changes(fbi, 1);
2022		omapfb_put_mem_region(ofbi->region);
2023
2024		if (r) {
2025			dev_err(fbdev->dev, "failed to change mode\n");
2026			return r;
2027		}
2028	}
2029
2030	/* Enable fb0 */
2031	if (fbdev->num_fbs > 0) {
2032		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
2033
2034		if (ofbi->num_overlays > 0) {
2035			struct omap_overlay *ovl = ofbi->overlays[0];
2036
2037			r = omapfb_overlay_enable(ovl, 1);
2038
2039			if (r) {
2040				dev_err(fbdev->dev,
2041						"failed to enable overlay\n");
2042				return r;
2043			}
2044		}
2045	}
2046
2047	DBG("create_framebuffers done\n");
2048
2049	return 0;
2050}
2051
2052static int omapfb_mode_to_timings(const char *mode_str,
2053		struct omap_video_timings *timings, u8 *bpp)
2054{
2055	struct fb_info *fbi;
2056	struct fb_var_screeninfo *var;
2057	struct fb_ops *fbops;
2058	int r;
2059
2060#ifdef CONFIG_OMAP2_DSS_VENC
2061	if (strcmp(mode_str, "pal") == 0) {
2062		*timings = omap_dss_pal_timings;
2063		*bpp = 24;
2064		return 0;
2065	} else if (strcmp(mode_str, "ntsc") == 0) {
2066		*timings = omap_dss_ntsc_timings;
2067		*bpp = 24;
2068		return 0;
2069	}
2070#endif
2071
2072	/* this is quite a hack, but I wanted to use the modedb and for
2073	 * that we need fb_info and var, so we create dummy ones */
2074
2075	*bpp = 0;
2076	fbi = NULL;
2077	var = NULL;
2078	fbops = NULL;
2079
2080	fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
2081	if (fbi == NULL) {
2082		r = -ENOMEM;
2083		goto err;
2084	}
2085
2086	var = kzalloc(sizeof(*var), GFP_KERNEL);
2087	if (var == NULL) {
2088		r = -ENOMEM;
2089		goto err;
2090	}
2091
2092	fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
2093	if (fbops == NULL) {
2094		r = -ENOMEM;
2095		goto err;
2096	}
2097
2098	fbi->fbops = fbops;
2099
2100	r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
2101	if (r == 0) {
2102		r = -EINVAL;
2103		goto err;
2104	}
2105
2106	timings->pixel_clock = PICOS2KHZ(var->pixclock);
2107	timings->hbp = var->left_margin;
2108	timings->hfp = var->right_margin;
2109	timings->vbp = var->upper_margin;
2110	timings->vfp = var->lower_margin;
2111	timings->hsw = var->hsync_len;
2112	timings->vsw = var->vsync_len;
2113	timings->x_res = var->xres;
2114	timings->y_res = var->yres;
2115
2116	switch (var->bits_per_pixel) {
2117	case 16:
2118		*bpp = 16;
2119		break;
2120	case 24:
2121	case 32:
2122	default:
2123		*bpp = 24;
2124		break;
2125	}
2126
2127	r = 0;
2128
2129err:
2130	kfree(fbi);
2131	kfree(var);
2132	kfree(fbops);
2133
2134	return r;
2135}
2136
2137static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
2138		struct omap_dss_device *display, char *mode_str)
2139{
2140	int r;
2141	u8 bpp;
2142	struct omap_video_timings timings, temp_timings;
2143
2144	r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2145	if (r)
2146		return r;
2147
2148	fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display;
2149	fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
2150	++fbdev->num_bpp_overrides;
2151
2152	if (display->driver->chec

Large files files are truncated, but you can click here to view the full file