162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/drivers/video/omap2/omapfb-main.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation
662306a36Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Some code and ideas taken from drivers/video/omap/ driver
962306a36Sopenharmony_ci * by Imre Deak.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/fb.h>
1662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1762306a36Sopenharmony_ci#include <linux/vmalloc.h>
1862306a36Sopenharmony_ci#include <linux/device.h>
1962306a36Sopenharmony_ci#include <linux/platform_device.h>
2062306a36Sopenharmony_ci#include <linux/omapfb.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <video/omapfb_dss.h>
2362306a36Sopenharmony_ci#include <video/omapvrfb.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "omapfb.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define MODULE_NAME     "omapfb"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define OMAPFB_PLANE_XRES_MIN		8
3062306a36Sopenharmony_ci#define OMAPFB_PLANE_YRES_MIN		8
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic char *def_mode;
3362306a36Sopenharmony_cistatic char *def_vram;
3462306a36Sopenharmony_cistatic bool def_vrfb;
3562306a36Sopenharmony_cistatic int def_rotate;
3662306a36Sopenharmony_cistatic bool def_mirror;
3762306a36Sopenharmony_cistatic bool auto_update;
3862306a36Sopenharmony_cistatic unsigned int auto_update_freq;
3962306a36Sopenharmony_cimodule_param(auto_update, bool, 0);
4062306a36Sopenharmony_cimodule_param(auto_update_freq, uint, 0644);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#ifdef DEBUG
4362306a36Sopenharmony_cibool omapfb_debug;
4462306a36Sopenharmony_cimodule_param_named(debug, omapfb_debug, bool, 0644);
4562306a36Sopenharmony_cistatic bool omapfb_test_pattern;
4662306a36Sopenharmony_cimodule_param_named(test, omapfb_test_pattern, bool, 0644);
4762306a36Sopenharmony_ci#endif
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
5062306a36Sopenharmony_cistatic int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
5162306a36Sopenharmony_ci		struct omap_dss_device *dssdev);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#ifdef DEBUG
5462306a36Sopenharmony_cistatic void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &fbi->var;
5762306a36Sopenharmony_ci	struct fb_fix_screeninfo *fix = &fbi->fix;
5862306a36Sopenharmony_ci	void __iomem *addr = fbi->screen_base;
5962306a36Sopenharmony_ci	const unsigned bytespp = var->bits_per_pixel >> 3;
6062306a36Sopenharmony_ci	const unsigned line_len = fix->line_length / bytespp;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	int r = (color >> 16) & 0xff;
6362306a36Sopenharmony_ci	int g = (color >> 8) & 0xff;
6462306a36Sopenharmony_ci	int b = (color >> 0) & 0xff;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (var->bits_per_pixel == 16) {
6762306a36Sopenharmony_ci		u16 __iomem *p = (u16 __iomem *)addr;
6862306a36Sopenharmony_ci		p += y * line_len + x;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci		r = r * 32 / 256;
7162306a36Sopenharmony_ci		g = g * 64 / 256;
7262306a36Sopenharmony_ci		b = b * 32 / 256;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		__raw_writew((r << 11) | (g << 5) | (b << 0), p);
7562306a36Sopenharmony_ci	} else if (var->bits_per_pixel == 24) {
7662306a36Sopenharmony_ci		u8 __iomem *p = (u8 __iomem *)addr;
7762306a36Sopenharmony_ci		p += (y * line_len + x) * 3;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		__raw_writeb(b, p + 0);
8062306a36Sopenharmony_ci		__raw_writeb(g, p + 1);
8162306a36Sopenharmony_ci		__raw_writeb(r, p + 2);
8262306a36Sopenharmony_ci	} else if (var->bits_per_pixel == 32) {
8362306a36Sopenharmony_ci		u32 __iomem *p = (u32 __iomem *)addr;
8462306a36Sopenharmony_ci		p += y * line_len + x;
8562306a36Sopenharmony_ci		__raw_writel(color, p);
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic void fill_fb(struct fb_info *fbi)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &fbi->var;
9262306a36Sopenharmony_ci	const short w = var->xres_virtual;
9362306a36Sopenharmony_ci	const short h = var->yres_virtual;
9462306a36Sopenharmony_ci	void __iomem *addr = fbi->screen_base;
9562306a36Sopenharmony_ci	int y, x;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (!addr)
9862306a36Sopenharmony_ci		return;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	for (y = 0; y < h; y++) {
10362306a36Sopenharmony_ci		for (x = 0; x < w; x++) {
10462306a36Sopenharmony_ci			if (x < 20 && y < 20)
10562306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0xffffff);
10662306a36Sopenharmony_ci			else if (x < 20 && (y > 20 && y < h - 20))
10762306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0xff);
10862306a36Sopenharmony_ci			else if (y < 20 && (x > 20 && x < w - 20))
10962306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0xff00);
11062306a36Sopenharmony_ci			else if (x > w - 20 && (y > 20 && y < h - 20))
11162306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0xff0000);
11262306a36Sopenharmony_ci			else if (y > h - 20 && (x > 20 && x < w - 20))
11362306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0xffff00);
11462306a36Sopenharmony_ci			else if (x == 20 || x == w - 20 ||
11562306a36Sopenharmony_ci					y == 20 || y == h - 20)
11662306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0xffffff);
11762306a36Sopenharmony_ci			else if (x == y || w - x == h - y)
11862306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0xff00ff);
11962306a36Sopenharmony_ci			else if (w - x == y || x == h - y)
12062306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0x00ffff);
12162306a36Sopenharmony_ci			else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
12262306a36Sopenharmony_ci				int t = x * 3 / w;
12362306a36Sopenharmony_ci				unsigned r = 0, g = 0, b = 0;
12462306a36Sopenharmony_ci				unsigned c;
12562306a36Sopenharmony_ci				if (var->bits_per_pixel == 16) {
12662306a36Sopenharmony_ci					if (t == 0)
12762306a36Sopenharmony_ci						b = (y % 32) * 256 / 32;
12862306a36Sopenharmony_ci					else if (t == 1)
12962306a36Sopenharmony_ci						g = (y % 64) * 256 / 64;
13062306a36Sopenharmony_ci					else if (t == 2)
13162306a36Sopenharmony_ci						r = (y % 32) * 256 / 32;
13262306a36Sopenharmony_ci				} else {
13362306a36Sopenharmony_ci					if (t == 0)
13462306a36Sopenharmony_ci						b = (y % 256);
13562306a36Sopenharmony_ci					else if (t == 1)
13662306a36Sopenharmony_ci						g = (y % 256);
13762306a36Sopenharmony_ci					else if (t == 2)
13862306a36Sopenharmony_ci						r = (y % 256);
13962306a36Sopenharmony_ci				}
14062306a36Sopenharmony_ci				c = (r << 16) | (g << 8) | (b << 0);
14162306a36Sopenharmony_ci				draw_pixel(fbi, x, y, c);
14262306a36Sopenharmony_ci			} else {
14362306a36Sopenharmony_ci				draw_pixel(fbi, x, y, 0);
14462306a36Sopenharmony_ci			}
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci#endif
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	const struct vrfb *vrfb = &ofbi->region->vrfb;
15362306a36Sopenharmony_ci	unsigned offset;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	switch (rot) {
15662306a36Sopenharmony_ci	case FB_ROTATE_UR:
15762306a36Sopenharmony_ci		offset = 0;
15862306a36Sopenharmony_ci		break;
15962306a36Sopenharmony_ci	case FB_ROTATE_CW:
16062306a36Sopenharmony_ci		offset = vrfb->yoffset;
16162306a36Sopenharmony_ci		break;
16262306a36Sopenharmony_ci	case FB_ROTATE_UD:
16362306a36Sopenharmony_ci		offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
16462306a36Sopenharmony_ci		break;
16562306a36Sopenharmony_ci	case FB_ROTATE_CCW:
16662306a36Sopenharmony_ci		offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
16762306a36Sopenharmony_ci		break;
16862306a36Sopenharmony_ci	default:
16962306a36Sopenharmony_ci		BUG();
17062306a36Sopenharmony_ci		return 0;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	offset *= vrfb->bytespp;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return offset;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
18162306a36Sopenharmony_ci		return ofbi->region->vrfb.paddr[rot]
18262306a36Sopenharmony_ci			+ omapfb_get_vrfb_offset(ofbi, rot);
18362306a36Sopenharmony_ci	} else {
18462306a36Sopenharmony_ci		return ofbi->region->paddr;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19162306a36Sopenharmony_ci		return ofbi->region->vrfb.paddr[0];
19262306a36Sopenharmony_ci	else
19362306a36Sopenharmony_ci		return ofbi->region->paddr;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19962306a36Sopenharmony_ci		return ofbi->region->vrfb.vaddr[0];
20062306a36Sopenharmony_ci	else
20162306a36Sopenharmony_ci		return ofbi->region->vaddr;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic struct omapfb_colormode omapfb_colormodes[] = {
20562306a36Sopenharmony_ci	{
20662306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_UYVY,
20762306a36Sopenharmony_ci		.bits_per_pixel = 16,
20862306a36Sopenharmony_ci		.nonstd = OMAPFB_COLOR_YUV422,
20962306a36Sopenharmony_ci	}, {
21062306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_YUV2,
21162306a36Sopenharmony_ci		.bits_per_pixel = 16,
21262306a36Sopenharmony_ci		.nonstd = OMAPFB_COLOR_YUY422,
21362306a36Sopenharmony_ci	}, {
21462306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_ARGB16,
21562306a36Sopenharmony_ci		.bits_per_pixel = 16,
21662306a36Sopenharmony_ci		.red	= { .length = 4, .offset = 8, .msb_right = 0 },
21762306a36Sopenharmony_ci		.green	= { .length = 4, .offset = 4, .msb_right = 0 },
21862306a36Sopenharmony_ci		.blue	= { .length = 4, .offset = 0, .msb_right = 0 },
21962306a36Sopenharmony_ci		.transp	= { .length = 4, .offset = 12, .msb_right = 0 },
22062306a36Sopenharmony_ci	}, {
22162306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_RGB16,
22262306a36Sopenharmony_ci		.bits_per_pixel = 16,
22362306a36Sopenharmony_ci		.red	= { .length = 5, .offset = 11, .msb_right = 0 },
22462306a36Sopenharmony_ci		.green	= { .length = 6, .offset = 5, .msb_right = 0 },
22562306a36Sopenharmony_ci		.blue	= { .length = 5, .offset = 0, .msb_right = 0 },
22662306a36Sopenharmony_ci		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
22762306a36Sopenharmony_ci	}, {
22862306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_RGB24P,
22962306a36Sopenharmony_ci		.bits_per_pixel = 24,
23062306a36Sopenharmony_ci		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
23162306a36Sopenharmony_ci		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
23262306a36Sopenharmony_ci		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
23362306a36Sopenharmony_ci		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
23462306a36Sopenharmony_ci	}, {
23562306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_RGB24U,
23662306a36Sopenharmony_ci		.bits_per_pixel = 32,
23762306a36Sopenharmony_ci		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
23862306a36Sopenharmony_ci		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
23962306a36Sopenharmony_ci		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
24062306a36Sopenharmony_ci		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
24162306a36Sopenharmony_ci	}, {
24262306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_ARGB32,
24362306a36Sopenharmony_ci		.bits_per_pixel = 32,
24462306a36Sopenharmony_ci		.red	= { .length = 8, .offset = 16, .msb_right = 0 },
24562306a36Sopenharmony_ci		.green	= { .length = 8, .offset = 8, .msb_right = 0 },
24662306a36Sopenharmony_ci		.blue	= { .length = 8, .offset = 0, .msb_right = 0 },
24762306a36Sopenharmony_ci		.transp	= { .length = 8, .offset = 24, .msb_right = 0 },
24862306a36Sopenharmony_ci	}, {
24962306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_RGBA32,
25062306a36Sopenharmony_ci		.bits_per_pixel = 32,
25162306a36Sopenharmony_ci		.red	= { .length = 8, .offset = 24, .msb_right = 0 },
25262306a36Sopenharmony_ci		.green	= { .length = 8, .offset = 16, .msb_right = 0 },
25362306a36Sopenharmony_ci		.blue	= { .length = 8, .offset = 8, .msb_right = 0 },
25462306a36Sopenharmony_ci		.transp	= { .length = 8, .offset = 0, .msb_right = 0 },
25562306a36Sopenharmony_ci	}, {
25662306a36Sopenharmony_ci		.dssmode = OMAP_DSS_COLOR_RGBX32,
25762306a36Sopenharmony_ci		.bits_per_pixel = 32,
25862306a36Sopenharmony_ci		.red	= { .length = 8, .offset = 24, .msb_right = 0 },
25962306a36Sopenharmony_ci		.green	= { .length = 8, .offset = 16, .msb_right = 0 },
26062306a36Sopenharmony_ci		.blue	= { .length = 8, .offset = 8, .msb_right = 0 },
26162306a36Sopenharmony_ci		.transp	= { .length = 0, .offset = 0, .msb_right = 0 },
26262306a36Sopenharmony_ci	},
26362306a36Sopenharmony_ci};
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	return f1->length == f2->length &&
26862306a36Sopenharmony_ci		f1->offset == f2->offset &&
26962306a36Sopenharmony_ci		f1->msb_right == f2->msb_right;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
27362306a36Sopenharmony_ci		struct omapfb_colormode *color)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	if (var->bits_per_pixel == 0 ||
27662306a36Sopenharmony_ci			var->red.length == 0 ||
27762306a36Sopenharmony_ci			var->blue.length == 0 ||
27862306a36Sopenharmony_ci			var->green.length == 0)
27962306a36Sopenharmony_ci		return false;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	return var->bits_per_pixel == color->bits_per_pixel &&
28262306a36Sopenharmony_ci		cmp_component(&var->red, &color->red) &&
28362306a36Sopenharmony_ci		cmp_component(&var->green, &color->green) &&
28462306a36Sopenharmony_ci		cmp_component(&var->blue, &color->blue) &&
28562306a36Sopenharmony_ci		cmp_component(&var->transp, &color->transp);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic void assign_colormode_to_var(struct fb_var_screeninfo *var,
28962306a36Sopenharmony_ci		struct omapfb_colormode *color)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	var->bits_per_pixel = color->bits_per_pixel;
29262306a36Sopenharmony_ci	var->nonstd = color->nonstd;
29362306a36Sopenharmony_ci	var->red = color->red;
29462306a36Sopenharmony_ci	var->green = color->green;
29562306a36Sopenharmony_ci	var->blue = color->blue;
29662306a36Sopenharmony_ci	var->transp = color->transp;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
30062306a36Sopenharmony_ci		enum omap_color_mode *mode)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	enum omap_color_mode dssmode;
30362306a36Sopenharmony_ci	int i;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* first match with nonstd field */
30662306a36Sopenharmony_ci	if (var->nonstd) {
30762306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
30862306a36Sopenharmony_ci			struct omapfb_colormode *m = &omapfb_colormodes[i];
30962306a36Sopenharmony_ci			if (var->nonstd == m->nonstd) {
31062306a36Sopenharmony_ci				assign_colormode_to_var(var, m);
31162306a36Sopenharmony_ci				*mode = m->dssmode;
31262306a36Sopenharmony_ci				return 0;
31362306a36Sopenharmony_ci			}
31462306a36Sopenharmony_ci		}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		return -EINVAL;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* then try exact match of bpp and colors */
32062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
32162306a36Sopenharmony_ci		struct omapfb_colormode *m = &omapfb_colormodes[i];
32262306a36Sopenharmony_ci		if (cmp_var_to_colormode(var, m)) {
32362306a36Sopenharmony_ci			assign_colormode_to_var(var, m);
32462306a36Sopenharmony_ci			*mode = m->dssmode;
32562306a36Sopenharmony_ci			return 0;
32662306a36Sopenharmony_ci		}
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* match with bpp if user has not filled color fields
33062306a36Sopenharmony_ci	 * properly */
33162306a36Sopenharmony_ci	switch (var->bits_per_pixel) {
33262306a36Sopenharmony_ci	case 1:
33362306a36Sopenharmony_ci		dssmode = OMAP_DSS_COLOR_CLUT1;
33462306a36Sopenharmony_ci		break;
33562306a36Sopenharmony_ci	case 2:
33662306a36Sopenharmony_ci		dssmode = OMAP_DSS_COLOR_CLUT2;
33762306a36Sopenharmony_ci		break;
33862306a36Sopenharmony_ci	case 4:
33962306a36Sopenharmony_ci		dssmode = OMAP_DSS_COLOR_CLUT4;
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	case 8:
34262306a36Sopenharmony_ci		dssmode = OMAP_DSS_COLOR_CLUT8;
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci	case 12:
34562306a36Sopenharmony_ci		dssmode = OMAP_DSS_COLOR_RGB12U;
34662306a36Sopenharmony_ci		break;
34762306a36Sopenharmony_ci	case 16:
34862306a36Sopenharmony_ci		dssmode = OMAP_DSS_COLOR_RGB16;
34962306a36Sopenharmony_ci		break;
35062306a36Sopenharmony_ci	case 24:
35162306a36Sopenharmony_ci		dssmode = OMAP_DSS_COLOR_RGB24P;
35262306a36Sopenharmony_ci		break;
35362306a36Sopenharmony_ci	case 32:
35462306a36Sopenharmony_ci		dssmode = OMAP_DSS_COLOR_RGB24U;
35562306a36Sopenharmony_ci		break;
35662306a36Sopenharmony_ci	default:
35762306a36Sopenharmony_ci		return -EINVAL;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
36162306a36Sopenharmony_ci		struct omapfb_colormode *m = &omapfb_colormodes[i];
36262306a36Sopenharmony_ci		if (dssmode == m->dssmode) {
36362306a36Sopenharmony_ci			assign_colormode_to_var(var, m);
36462306a36Sopenharmony_ci			*mode = m->dssmode;
36562306a36Sopenharmony_ci			return 0;
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	return -EINVAL;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int check_fb_res_bounds(struct fb_var_screeninfo *var)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	int xres_min = OMAPFB_PLANE_XRES_MIN;
37562306a36Sopenharmony_ci	int xres_max = 2048;
37662306a36Sopenharmony_ci	int yres_min = OMAPFB_PLANE_YRES_MIN;
37762306a36Sopenharmony_ci	int yres_max = 2048;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* XXX: some applications seem to set virtual res to 0. */
38062306a36Sopenharmony_ci	if (var->xres_virtual == 0)
38162306a36Sopenharmony_ci		var->xres_virtual = var->xres;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (var->yres_virtual == 0)
38462306a36Sopenharmony_ci		var->yres_virtual = var->yres;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
38762306a36Sopenharmony_ci		return -EINVAL;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (var->xres < xres_min)
39062306a36Sopenharmony_ci		var->xres = xres_min;
39162306a36Sopenharmony_ci	if (var->yres < yres_min)
39262306a36Sopenharmony_ci		var->yres = yres_min;
39362306a36Sopenharmony_ci	if (var->xres > xres_max)
39462306a36Sopenharmony_ci		var->xres = xres_max;
39562306a36Sopenharmony_ci	if (var->yres > yres_max)
39662306a36Sopenharmony_ci		var->yres = yres_max;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (var->xres > var->xres_virtual)
39962306a36Sopenharmony_ci		var->xres = var->xres_virtual;
40062306a36Sopenharmony_ci	if (var->yres > var->yres_virtual)
40162306a36Sopenharmony_ci		var->yres = var->yres_virtual;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	return 0;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic void shrink_height(unsigned long max_frame_size,
40762306a36Sopenharmony_ci		struct fb_var_screeninfo *var)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	DBG("can't fit FB into memory, reducing y\n");
41062306a36Sopenharmony_ci	var->yres_virtual = max_frame_size /
41162306a36Sopenharmony_ci		(var->xres_virtual * var->bits_per_pixel >> 3);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
41462306a36Sopenharmony_ci		var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (var->yres > var->yres_virtual)
41762306a36Sopenharmony_ci		var->yres = var->yres_virtual;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic void shrink_width(unsigned long max_frame_size,
42162306a36Sopenharmony_ci		struct fb_var_screeninfo *var)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	DBG("can't fit FB into memory, reducing x\n");
42462306a36Sopenharmony_ci	var->xres_virtual = max_frame_size / var->yres_virtual /
42562306a36Sopenharmony_ci		(var->bits_per_pixel >> 3);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
42862306a36Sopenharmony_ci		var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (var->xres > var->xres_virtual)
43162306a36Sopenharmony_ci		var->xres = var->xres_virtual;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic int check_vrfb_fb_size(unsigned long region_size,
43562306a36Sopenharmony_ci		const struct fb_var_screeninfo *var)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
43862306a36Sopenharmony_ci		var->yres_virtual, var->bits_per_pixel >> 3);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	return min_phys_size > region_size ? -EINVAL : 0;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic int check_fb_size(const struct omapfb_info *ofbi,
44462306a36Sopenharmony_ci		struct fb_var_screeninfo *var)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	unsigned long max_frame_size = ofbi->region->size;
44762306a36Sopenharmony_ci	int bytespp = var->bits_per_pixel >> 3;
44862306a36Sopenharmony_ci	unsigned long line_size = var->xres_virtual * bytespp;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
45162306a36Sopenharmony_ci		/* One needs to check for both VRFB and OMAPFB limitations. */
45262306a36Sopenharmony_ci		if (check_vrfb_fb_size(max_frame_size, var))
45362306a36Sopenharmony_ci			shrink_height(omap_vrfb_max_height(
45462306a36Sopenharmony_ci				max_frame_size, var->xres_virtual, bytespp) *
45562306a36Sopenharmony_ci				line_size, var);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		if (check_vrfb_fb_size(max_frame_size, var)) {
45862306a36Sopenharmony_ci			DBG("cannot fit FB to memory\n");
45962306a36Sopenharmony_ci			return -EINVAL;
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		return 0;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	if (line_size * var->yres_virtual > max_frame_size)
46862306a36Sopenharmony_ci		shrink_height(max_frame_size, var);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (line_size * var->yres_virtual > max_frame_size) {
47162306a36Sopenharmony_ci		shrink_width(max_frame_size, var);
47262306a36Sopenharmony_ci		line_size = var->xres_virtual * bytespp;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (line_size * var->yres_virtual > max_frame_size) {
47662306a36Sopenharmony_ci		DBG("cannot fit FB to memory\n");
47762306a36Sopenharmony_ci		return -EINVAL;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	return 0;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci/*
48462306a36Sopenharmony_ci * Consider if VRFB assisted rotation is in use and if the virtual space for
48562306a36Sopenharmony_ci * the zero degree view needs to be mapped. The need for mapping also acts as
48662306a36Sopenharmony_ci * the trigger for setting up the hardware on the context in question. This
48762306a36Sopenharmony_ci * ensures that one does not attempt to access the virtual view before the
48862306a36Sopenharmony_ci * hardware is serving the address translations.
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic int setup_vrfb_rotation(struct fb_info *fbi)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
49362306a36Sopenharmony_ci	struct omapfb2_mem_region *rg = ofbi->region;
49462306a36Sopenharmony_ci	struct vrfb *vrfb = &rg->vrfb;
49562306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &fbi->var;
49662306a36Sopenharmony_ci	struct fb_fix_screeninfo *fix = &fbi->fix;
49762306a36Sopenharmony_ci	unsigned bytespp;
49862306a36Sopenharmony_ci	bool yuv_mode;
49962306a36Sopenharmony_ci	enum omap_color_mode mode;
50062306a36Sopenharmony_ci	int r;
50162306a36Sopenharmony_ci	bool reconf;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
50462306a36Sopenharmony_ci		return 0;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	DBG("setup_vrfb_rotation\n");
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	r = fb_mode_to_dss_mode(var, &mode);
50962306a36Sopenharmony_ci	if (r)
51062306a36Sopenharmony_ci		return r;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	bytespp = var->bits_per_pixel >> 3;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/* We need to reconfigure VRFB if the resolution changes, if yuv mode
51762306a36Sopenharmony_ci	 * is enabled/disabled, or if bytes per pixel changes */
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* XXX we shouldn't allow this when framebuffer is mmapped */
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	reconf = false;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (yuv_mode != vrfb->yuv_mode)
52462306a36Sopenharmony_ci		reconf = true;
52562306a36Sopenharmony_ci	else if (bytespp != vrfb->bytespp)
52662306a36Sopenharmony_ci		reconf = true;
52762306a36Sopenharmony_ci	else if (vrfb->xres != var->xres_virtual ||
52862306a36Sopenharmony_ci			vrfb->yres != var->yres_virtual)
52962306a36Sopenharmony_ci		reconf = true;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (vrfb->vaddr[0] && reconf) {
53262306a36Sopenharmony_ci		fbi->screen_base = NULL;
53362306a36Sopenharmony_ci		fix->smem_start = 0;
53462306a36Sopenharmony_ci		fix->smem_len = 0;
53562306a36Sopenharmony_ci		iounmap(vrfb->vaddr[0]);
53662306a36Sopenharmony_ci		vrfb->vaddr[0] = NULL;
53762306a36Sopenharmony_ci		DBG("setup_vrfb_rotation: reset fb\n");
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (vrfb->vaddr[0])
54162306a36Sopenharmony_ci		return 0;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	omap_vrfb_setup(&rg->vrfb, rg->paddr,
54462306a36Sopenharmony_ci			var->xres_virtual,
54562306a36Sopenharmony_ci			var->yres_virtual,
54662306a36Sopenharmony_ci			bytespp, yuv_mode);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	/* Now one can ioremap the 0 angle view */
54962306a36Sopenharmony_ci	r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
55062306a36Sopenharmony_ci	if (r)
55162306a36Sopenharmony_ci		return r;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* used by open/write in fbmem.c */
55462306a36Sopenharmony_ci	fbi->screen_base = ofbi->region->vrfb.vaddr[0];
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	fix->smem_start = ofbi->region->vrfb.paddr[0];
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	switch (var->nonstd) {
55962306a36Sopenharmony_ci	case OMAPFB_COLOR_YUV422:
56062306a36Sopenharmony_ci	case OMAPFB_COLOR_YUY422:
56162306a36Sopenharmony_ci		fix->line_length =
56262306a36Sopenharmony_ci			(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
56362306a36Sopenharmony_ci		break;
56462306a36Sopenharmony_ci	default:
56562306a36Sopenharmony_ci		fix->line_length =
56662306a36Sopenharmony_ci			(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
56762306a36Sopenharmony_ci		break;
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	fix->smem_len = var->yres_virtual * fix->line_length;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return 0;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ciint dss_mode_to_fb_mode(enum omap_color_mode dssmode,
57662306a36Sopenharmony_ci			struct fb_var_screeninfo *var)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	int i;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
58162306a36Sopenharmony_ci		struct omapfb_colormode *mode = &omapfb_colormodes[i];
58262306a36Sopenharmony_ci		if (dssmode == mode->dssmode) {
58362306a36Sopenharmony_ci			assign_colormode_to_var(var, mode);
58462306a36Sopenharmony_ci			return 0;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci	return -ENOENT;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_civoid set_fb_fix(struct fb_info *fbi)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct fb_fix_screeninfo *fix = &fbi->fix;
59362306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &fbi->var;
59462306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
59562306a36Sopenharmony_ci	struct omapfb2_mem_region *rg = ofbi->region;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	DBG("set_fb_fix\n");
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* used by open/write in fbmem.c */
60062306a36Sopenharmony_ci	fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* used by mmap in fbmem.c */
60362306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
60462306a36Sopenharmony_ci		switch (var->nonstd) {
60562306a36Sopenharmony_ci		case OMAPFB_COLOR_YUV422:
60662306a36Sopenharmony_ci		case OMAPFB_COLOR_YUY422:
60762306a36Sopenharmony_ci			fix->line_length =
60862306a36Sopenharmony_ci				(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
60962306a36Sopenharmony_ci			break;
61062306a36Sopenharmony_ci		default:
61162306a36Sopenharmony_ci			fix->line_length =
61262306a36Sopenharmony_ci				(OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
61362306a36Sopenharmony_ci			break;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		fix->smem_len = var->yres_virtual * fix->line_length;
61762306a36Sopenharmony_ci	} else {
61862306a36Sopenharmony_ci		fix->line_length =
61962306a36Sopenharmony_ci			(var->xres_virtual * var->bits_per_pixel) >> 3;
62062306a36Sopenharmony_ci		fix->smem_len = rg->size;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	fix->smem_start = omapfb_get_region_paddr(ofbi);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	fix->type = FB_TYPE_PACKED_PIXELS;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (var->nonstd)
62862306a36Sopenharmony_ci		fix->visual = FB_VISUAL_PSEUDOCOLOR;
62962306a36Sopenharmony_ci	else {
63062306a36Sopenharmony_ci		switch (var->bits_per_pixel) {
63162306a36Sopenharmony_ci		case 32:
63262306a36Sopenharmony_ci		case 24:
63362306a36Sopenharmony_ci		case 16:
63462306a36Sopenharmony_ci		case 12:
63562306a36Sopenharmony_ci			fix->visual = FB_VISUAL_TRUECOLOR;
63662306a36Sopenharmony_ci			/* 12bpp is stored in 16 bits */
63762306a36Sopenharmony_ci			break;
63862306a36Sopenharmony_ci		case 1:
63962306a36Sopenharmony_ci		case 2:
64062306a36Sopenharmony_ci		case 4:
64162306a36Sopenharmony_ci		case 8:
64262306a36Sopenharmony_ci			fix->visual = FB_VISUAL_PSEUDOCOLOR;
64362306a36Sopenharmony_ci			break;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	fix->accel = FB_ACCEL_NONE;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	fix->xpanstep = 1;
65062306a36Sopenharmony_ci	fix->ypanstep = 1;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci/* check new var and possibly modify it to be ok */
65462306a36Sopenharmony_ciint check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
65762306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
65862306a36Sopenharmony_ci	enum omap_color_mode mode = 0;
65962306a36Sopenharmony_ci	int i;
66062306a36Sopenharmony_ci	int r;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	DBG("check_fb_var %d\n", ofbi->id);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	WARN_ON(!atomic_read(&ofbi->region->lock_count));
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	r = fb_mode_to_dss_mode(var, &mode);
66762306a36Sopenharmony_ci	if (r) {
66862306a36Sopenharmony_ci		DBG("cannot convert var to omap dss mode\n");
66962306a36Sopenharmony_ci		return r;
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	for (i = 0; i < ofbi->num_overlays; ++i) {
67362306a36Sopenharmony_ci		if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
67462306a36Sopenharmony_ci			DBG("invalid mode\n");
67562306a36Sopenharmony_ci			return -EINVAL;
67662306a36Sopenharmony_ci		}
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (var->rotate > 3)
68062306a36Sopenharmony_ci		return -EINVAL;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (check_fb_res_bounds(var))
68362306a36Sopenharmony_ci		return -EINVAL;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/* When no memory is allocated ignore the size check */
68662306a36Sopenharmony_ci	if (ofbi->region->size != 0 && check_fb_size(ofbi, var))
68762306a36Sopenharmony_ci		return -EINVAL;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	if (var->xres + var->xoffset > var->xres_virtual)
69062306a36Sopenharmony_ci		var->xoffset = var->xres_virtual - var->xres;
69162306a36Sopenharmony_ci	if (var->yres + var->yoffset > var->yres_virtual)
69262306a36Sopenharmony_ci		var->yoffset = var->yres_virtual - var->yres;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
69562306a36Sopenharmony_ci			var->xres, var->yres,
69662306a36Sopenharmony_ci			var->xres_virtual, var->yres_virtual);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (display && display->driver->get_dimensions) {
69962306a36Sopenharmony_ci		u32 w, h;
70062306a36Sopenharmony_ci		display->driver->get_dimensions(display, &w, &h);
70162306a36Sopenharmony_ci		var->width = DIV_ROUND_CLOSEST(w, 1000);
70262306a36Sopenharmony_ci		var->height = DIV_ROUND_CLOSEST(h, 1000);
70362306a36Sopenharmony_ci	} else {
70462306a36Sopenharmony_ci		var->height = -1;
70562306a36Sopenharmony_ci		var->width = -1;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	var->grayscale          = 0;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (display && display->driver->get_timings) {
71162306a36Sopenharmony_ci		struct omap_video_timings timings;
71262306a36Sopenharmony_ci		display->driver->get_timings(display, &timings);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		/* pixclock in ps, the rest in pixclock */
71562306a36Sopenharmony_ci		var->pixclock = timings.pixelclock != 0 ?
71662306a36Sopenharmony_ci			KHZ2PICOS(timings.pixelclock / 1000) :
71762306a36Sopenharmony_ci			0;
71862306a36Sopenharmony_ci		var->left_margin = timings.hbp;
71962306a36Sopenharmony_ci		var->right_margin = timings.hfp;
72062306a36Sopenharmony_ci		var->upper_margin = timings.vbp;
72162306a36Sopenharmony_ci		var->lower_margin = timings.vfp;
72262306a36Sopenharmony_ci		var->hsync_len = timings.hsw;
72362306a36Sopenharmony_ci		var->vsync_len = timings.vsw;
72462306a36Sopenharmony_ci		var->sync |= timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH ?
72562306a36Sopenharmony_ci				FB_SYNC_HOR_HIGH_ACT : 0;
72662306a36Sopenharmony_ci		var->sync |= timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH ?
72762306a36Sopenharmony_ci				FB_SYNC_VERT_HIGH_ACT : 0;
72862306a36Sopenharmony_ci		var->vmode = timings.interlace ?
72962306a36Sopenharmony_ci				FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
73062306a36Sopenharmony_ci	} else {
73162306a36Sopenharmony_ci		var->pixclock = 0;
73262306a36Sopenharmony_ci		var->left_margin = 0;
73362306a36Sopenharmony_ci		var->right_margin = 0;
73462306a36Sopenharmony_ci		var->upper_margin = 0;
73562306a36Sopenharmony_ci		var->lower_margin = 0;
73662306a36Sopenharmony_ci		var->hsync_len = 0;
73762306a36Sopenharmony_ci		var->vsync_len = 0;
73862306a36Sopenharmony_ci		var->sync = 0;
73962306a36Sopenharmony_ci		var->vmode = FB_VMODE_NONINTERLACED;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return 0;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci/*
74662306a36Sopenharmony_ci * ---------------------------------------------------------------------------
74762306a36Sopenharmony_ci * fbdev framework callbacks
74862306a36Sopenharmony_ci * ---------------------------------------------------------------------------
74962306a36Sopenharmony_ci */
75062306a36Sopenharmony_cistatic int omapfb_open(struct fb_info *fbi, int user)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	return 0;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic int omapfb_release(struct fb_info *fbi, int user)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	return 0;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var,
76162306a36Sopenharmony_ci		const struct fb_fix_screeninfo *fix, int rotation)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	unsigned offset;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	offset = var->yoffset * fix->line_length +
76662306a36Sopenharmony_ci		var->xoffset * (var->bits_per_pixel >> 3);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	return offset;
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
77262306a36Sopenharmony_ci		const struct fb_fix_screeninfo *fix, int rotation)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	unsigned offset;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (rotation == FB_ROTATE_UD)
77762306a36Sopenharmony_ci		offset = (var->yres_virtual - var->yres) *
77862306a36Sopenharmony_ci			fix->line_length;
77962306a36Sopenharmony_ci	else if (rotation == FB_ROTATE_CW)
78062306a36Sopenharmony_ci		offset = (var->yres_virtual - var->yres) *
78162306a36Sopenharmony_ci			(var->bits_per_pixel >> 3);
78262306a36Sopenharmony_ci	else
78362306a36Sopenharmony_ci		offset = 0;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	if (rotation == FB_ROTATE_UR)
78662306a36Sopenharmony_ci		offset += var->yoffset * fix->line_length +
78762306a36Sopenharmony_ci			var->xoffset * (var->bits_per_pixel >> 3);
78862306a36Sopenharmony_ci	else if (rotation == FB_ROTATE_UD)
78962306a36Sopenharmony_ci		offset -= var->yoffset * fix->line_length +
79062306a36Sopenharmony_ci			var->xoffset * (var->bits_per_pixel >> 3);
79162306a36Sopenharmony_ci	else if (rotation == FB_ROTATE_CW)
79262306a36Sopenharmony_ci		offset -= var->xoffset * fix->line_length +
79362306a36Sopenharmony_ci			var->yoffset * (var->bits_per_pixel >> 3);
79462306a36Sopenharmony_ci	else if (rotation == FB_ROTATE_CCW)
79562306a36Sopenharmony_ci		offset += var->xoffset * fix->line_length +
79662306a36Sopenharmony_ci			var->yoffset * (var->bits_per_pixel >> 3);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	return offset;
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic void omapfb_calc_addr(const struct omapfb_info *ofbi,
80262306a36Sopenharmony_ci			     const struct fb_var_screeninfo *var,
80362306a36Sopenharmony_ci			     const struct fb_fix_screeninfo *fix,
80462306a36Sopenharmony_ci			     int rotation, u32 *paddr)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	u32 data_start_p;
80762306a36Sopenharmony_ci	int offset;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
81062306a36Sopenharmony_ci		data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
81162306a36Sopenharmony_ci	else
81262306a36Sopenharmony_ci		data_start_p = omapfb_get_region_paddr(ofbi);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
81562306a36Sopenharmony_ci		offset = calc_rotation_offset_vrfb(var, fix, rotation);
81662306a36Sopenharmony_ci	else
81762306a36Sopenharmony_ci		offset = calc_rotation_offset_dma(var, fix, rotation);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	data_start_p += offset;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	if (offset)
82262306a36Sopenharmony_ci		DBG("offset %d, %d = %d\n",
82362306a36Sopenharmony_ci		    var->xoffset, var->yoffset, offset);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	DBG("paddr %x\n", data_start_p);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	*paddr = data_start_p;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci/* setup overlay according to the fb */
83162306a36Sopenharmony_ciint omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
83262306a36Sopenharmony_ci		u16 posx, u16 posy, u16 outw, u16 outh)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	int r = 0;
83562306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
83662306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &fbi->var;
83762306a36Sopenharmony_ci	struct fb_fix_screeninfo *fix = &fbi->fix;
83862306a36Sopenharmony_ci	enum omap_color_mode mode = 0;
83962306a36Sopenharmony_ci	u32 data_start_p = 0;
84062306a36Sopenharmony_ci	struct omap_overlay_info info;
84162306a36Sopenharmony_ci	int xres, yres;
84262306a36Sopenharmony_ci	int screen_width;
84362306a36Sopenharmony_ci	int mirror;
84462306a36Sopenharmony_ci	int rotation = var->rotate;
84562306a36Sopenharmony_ci	int i;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	WARN_ON(!atomic_read(&ofbi->region->lock_count));
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	for (i = 0; i < ofbi->num_overlays; i++) {
85062306a36Sopenharmony_ci		if (ovl != ofbi->overlays[i])
85162306a36Sopenharmony_ci			continue;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci		rotation = (rotation + ofbi->rotation[i]) % 4;
85462306a36Sopenharmony_ci		break;
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
85862306a36Sopenharmony_ci			posx, posy, outw, outh);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
86162306a36Sopenharmony_ci		xres = var->yres;
86262306a36Sopenharmony_ci		yres = var->xres;
86362306a36Sopenharmony_ci	} else {
86462306a36Sopenharmony_ci		xres = var->xres;
86562306a36Sopenharmony_ci		yres = var->yres;
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (ofbi->region->size)
86962306a36Sopenharmony_ci		omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	r = fb_mode_to_dss_mode(var, &mode);
87262306a36Sopenharmony_ci	if (r) {
87362306a36Sopenharmony_ci		DBG("fb_mode_to_dss_mode failed");
87462306a36Sopenharmony_ci		goto err;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	switch (var->nonstd) {
87862306a36Sopenharmony_ci	case OMAPFB_COLOR_YUV422:
87962306a36Sopenharmony_ci	case OMAPFB_COLOR_YUY422:
88062306a36Sopenharmony_ci		if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
88162306a36Sopenharmony_ci			screen_width = fix->line_length
88262306a36Sopenharmony_ci				/ (var->bits_per_pixel >> 2);
88362306a36Sopenharmony_ci			break;
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci		fallthrough;
88662306a36Sopenharmony_ci	default:
88762306a36Sopenharmony_ci		screen_width = fix->line_length / (var->bits_per_pixel >> 3);
88862306a36Sopenharmony_ci		break;
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	ovl->get_overlay_info(ovl, &info);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
89462306a36Sopenharmony_ci		mirror = 0;
89562306a36Sopenharmony_ci	else
89662306a36Sopenharmony_ci		mirror = ofbi->mirror;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	info.paddr = data_start_p;
89962306a36Sopenharmony_ci	info.screen_width = screen_width;
90062306a36Sopenharmony_ci	info.width = xres;
90162306a36Sopenharmony_ci	info.height = yres;
90262306a36Sopenharmony_ci	info.color_mode = mode;
90362306a36Sopenharmony_ci	info.rotation_type = ofbi->rotation_type;
90462306a36Sopenharmony_ci	info.rotation = rotation;
90562306a36Sopenharmony_ci	info.mirror = mirror;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	info.pos_x = posx;
90862306a36Sopenharmony_ci	info.pos_y = posy;
90962306a36Sopenharmony_ci	info.out_width = outw;
91062306a36Sopenharmony_ci	info.out_height = outh;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	r = ovl->set_overlay_info(ovl, &info);
91362306a36Sopenharmony_ci	if (r) {
91462306a36Sopenharmony_ci		DBG("ovl->setup_overlay_info failed\n");
91562306a36Sopenharmony_ci		goto err;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	return 0;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cierr:
92162306a36Sopenharmony_ci	DBG("setup_overlay failed\n");
92262306a36Sopenharmony_ci	return r;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci/* apply var to the overlay */
92662306a36Sopenharmony_ciint omapfb_apply_changes(struct fb_info *fbi, int init)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	int r = 0;
92962306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
93062306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &fbi->var;
93162306a36Sopenharmony_ci	struct omap_overlay *ovl;
93262306a36Sopenharmony_ci	u16 posx, posy;
93362306a36Sopenharmony_ci	u16 outw, outh;
93462306a36Sopenharmony_ci	int i;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci#ifdef DEBUG
93762306a36Sopenharmony_ci	if (omapfb_test_pattern)
93862306a36Sopenharmony_ci		fill_fb(fbi);
93962306a36Sopenharmony_ci#endif
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	WARN_ON(!atomic_read(&ofbi->region->lock_count));
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	for (i = 0; i < ofbi->num_overlays; i++) {
94462306a36Sopenharmony_ci		ovl = ofbi->overlays[i];
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci		if (ofbi->region->size == 0) {
94962306a36Sopenharmony_ci			/* the fb is not available. disable the overlay */
95062306a36Sopenharmony_ci			omapfb_overlay_enable(ovl, 0);
95162306a36Sopenharmony_ci			if (!init && ovl->manager)
95262306a36Sopenharmony_ci				ovl->manager->apply(ovl->manager);
95362306a36Sopenharmony_ci			continue;
95462306a36Sopenharmony_ci		}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci		if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
95762306a36Sopenharmony_ci			int rotation = (var->rotate + ofbi->rotation[i]) % 4;
95862306a36Sopenharmony_ci			if (rotation == FB_ROTATE_CW ||
95962306a36Sopenharmony_ci					rotation == FB_ROTATE_CCW) {
96062306a36Sopenharmony_ci				outw = var->yres;
96162306a36Sopenharmony_ci				outh = var->xres;
96262306a36Sopenharmony_ci			} else {
96362306a36Sopenharmony_ci				outw = var->xres;
96462306a36Sopenharmony_ci				outh = var->yres;
96562306a36Sopenharmony_ci			}
96662306a36Sopenharmony_ci		} else {
96762306a36Sopenharmony_ci			struct omap_overlay_info info;
96862306a36Sopenharmony_ci			ovl->get_overlay_info(ovl, &info);
96962306a36Sopenharmony_ci			outw = info.out_width;
97062306a36Sopenharmony_ci			outh = info.out_height;
97162306a36Sopenharmony_ci		}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci		if (init) {
97462306a36Sopenharmony_ci			posx = 0;
97562306a36Sopenharmony_ci			posy = 0;
97662306a36Sopenharmony_ci		} else {
97762306a36Sopenharmony_ci			struct omap_overlay_info info;
97862306a36Sopenharmony_ci			ovl->get_overlay_info(ovl, &info);
97962306a36Sopenharmony_ci			posx = info.pos_x;
98062306a36Sopenharmony_ci			posy = info.pos_y;
98162306a36Sopenharmony_ci		}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci		r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
98462306a36Sopenharmony_ci		if (r)
98562306a36Sopenharmony_ci			goto err;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		if (!init && ovl->manager)
98862306a36Sopenharmony_ci			ovl->manager->apply(ovl->manager);
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci	return 0;
99162306a36Sopenharmony_cierr:
99262306a36Sopenharmony_ci	DBG("apply_changes failed\n");
99362306a36Sopenharmony_ci	return r;
99462306a36Sopenharmony_ci}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci/* checks var and eventually tweaks it to something supported,
99762306a36Sopenharmony_ci * DO NOT MODIFY PAR */
99862306a36Sopenharmony_cistatic int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
100162306a36Sopenharmony_ci	int r;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	DBG("check_var(%d)\n", FB2OFB(fbi)->id);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	omapfb_get_mem_region(ofbi->region);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	r = check_fb_var(fbi, var);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	omapfb_put_mem_region(ofbi->region);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	return r;
101262306a36Sopenharmony_ci}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci/* set the video mode according to info->var */
101562306a36Sopenharmony_cistatic int omapfb_set_par(struct fb_info *fbi)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
101862306a36Sopenharmony_ci	int r;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	DBG("set_par(%d)\n", FB2OFB(fbi)->id);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	omapfb_get_mem_region(ofbi->region);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	set_fb_fix(fbi);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	r = setup_vrfb_rotation(fbi);
102762306a36Sopenharmony_ci	if (r)
102862306a36Sopenharmony_ci		goto out;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	r = omapfb_apply_changes(fbi, 0);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci out:
103362306a36Sopenharmony_ci	omapfb_put_mem_region(ofbi->region);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	return r;
103662306a36Sopenharmony_ci}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_cistatic int omapfb_pan_display(struct fb_var_screeninfo *var,
103962306a36Sopenharmony_ci		struct fb_info *fbi)
104062306a36Sopenharmony_ci{
104162306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
104262306a36Sopenharmony_ci	struct fb_var_screeninfo new_var;
104362306a36Sopenharmony_ci	int r;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	if (var->xoffset == fbi->var.xoffset &&
104862306a36Sopenharmony_ci	    var->yoffset == fbi->var.yoffset)
104962306a36Sopenharmony_ci		return 0;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	new_var = fbi->var;
105262306a36Sopenharmony_ci	new_var.xoffset = var->xoffset;
105362306a36Sopenharmony_ci	new_var.yoffset = var->yoffset;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	fbi->var = new_var;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	omapfb_get_mem_region(ofbi->region);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	r = omapfb_apply_changes(fbi, 0);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	omapfb_put_mem_region(ofbi->region);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	return r;
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_cistatic void mmap_user_open(struct vm_area_struct *vma)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	struct omapfb2_mem_region *rg = vma->vm_private_data;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	omapfb_get_mem_region(rg);
107162306a36Sopenharmony_ci	atomic_inc(&rg->map_count);
107262306a36Sopenharmony_ci	omapfb_put_mem_region(rg);
107362306a36Sopenharmony_ci}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cistatic void mmap_user_close(struct vm_area_struct *vma)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	struct omapfb2_mem_region *rg = vma->vm_private_data;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	omapfb_get_mem_region(rg);
108062306a36Sopenharmony_ci	atomic_dec(&rg->map_count);
108162306a36Sopenharmony_ci	omapfb_put_mem_region(rg);
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic const struct vm_operations_struct mmap_user_ops = {
108562306a36Sopenharmony_ci	.open = mmap_user_open,
108662306a36Sopenharmony_ci	.close = mmap_user_close,
108762306a36Sopenharmony_ci};
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_cistatic int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
109062306a36Sopenharmony_ci{
109162306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
109262306a36Sopenharmony_ci	struct fb_fix_screeninfo *fix = &fbi->fix;
109362306a36Sopenharmony_ci	struct omapfb2_mem_region *rg;
109462306a36Sopenharmony_ci	unsigned long start;
109562306a36Sopenharmony_ci	u32 len;
109662306a36Sopenharmony_ci	int r;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	rg = omapfb_get_mem_region(ofbi->region);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	start = omapfb_get_region_paddr(ofbi);
110162306a36Sopenharmony_ci	len = fix->smem_len;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	DBG("user mmap region start %lx, len %d, off %lx\n", start, len,
110462306a36Sopenharmony_ci			vma->vm_pgoff << PAGE_SHIFT);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
110762306a36Sopenharmony_ci	vma->vm_ops = &mmap_user_ops;
110862306a36Sopenharmony_ci	vma->vm_private_data = rg;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	r = vm_iomap_memory(vma, start, len);
111162306a36Sopenharmony_ci	if (r)
111262306a36Sopenharmony_ci		goto error;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	/* vm_ops.open won't be called for mmap itself. */
111562306a36Sopenharmony_ci	atomic_inc(&rg->map_count);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	omapfb_put_mem_region(rg);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	return 0;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_cierror:
112262306a36Sopenharmony_ci	omapfb_put_mem_region(ofbi->region);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	return r;
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci/* Store a single color palette entry into a pseudo palette or the hardware
112862306a36Sopenharmony_ci * palette if one is available. For now we support only 16bpp and thus store
112962306a36Sopenharmony_ci * the entry only to the pseudo palette.
113062306a36Sopenharmony_ci */
113162306a36Sopenharmony_cistatic int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
113262306a36Sopenharmony_ci		u_int blue, u_int transp, int update_hw_pal)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	/*struct omapfb_info *ofbi = FB2OFB(fbi);*/
113562306a36Sopenharmony_ci	/*struct omapfb2_device *fbdev = ofbi->fbdev;*/
113662306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &fbi->var;
113762306a36Sopenharmony_ci	int r = 0;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/*switch (plane->color_mode) {*/
114262306a36Sopenharmony_ci	switch (mode) {
114362306a36Sopenharmony_ci	case OMAPFB_COLOR_YUV422:
114462306a36Sopenharmony_ci	case OMAPFB_COLOR_YUV420:
114562306a36Sopenharmony_ci	case OMAPFB_COLOR_YUY422:
114662306a36Sopenharmony_ci		r = -EINVAL;
114762306a36Sopenharmony_ci		break;
114862306a36Sopenharmony_ci	case OMAPFB_COLOR_CLUT_8BPP:
114962306a36Sopenharmony_ci	case OMAPFB_COLOR_CLUT_4BPP:
115062306a36Sopenharmony_ci	case OMAPFB_COLOR_CLUT_2BPP:
115162306a36Sopenharmony_ci	case OMAPFB_COLOR_CLUT_1BPP:
115262306a36Sopenharmony_ci		/*
115362306a36Sopenharmony_ci		   if (fbdev->ctrl->setcolreg)
115462306a36Sopenharmony_ci		   r = fbdev->ctrl->setcolreg(regno, red, green, blue,
115562306a36Sopenharmony_ci		   transp, update_hw_pal);
115662306a36Sopenharmony_ci		   */
115762306a36Sopenharmony_ci		r = -EINVAL;
115862306a36Sopenharmony_ci		break;
115962306a36Sopenharmony_ci	case OMAPFB_COLOR_RGB565:
116062306a36Sopenharmony_ci	case OMAPFB_COLOR_RGB444:
116162306a36Sopenharmony_ci	case OMAPFB_COLOR_RGB24P:
116262306a36Sopenharmony_ci	case OMAPFB_COLOR_RGB24U:
116362306a36Sopenharmony_ci		if (regno < 16) {
116462306a36Sopenharmony_ci			u32 pal;
116562306a36Sopenharmony_ci			pal = ((red >> (16 - var->red.length)) <<
116662306a36Sopenharmony_ci					var->red.offset) |
116762306a36Sopenharmony_ci				((green >> (16 - var->green.length)) <<
116862306a36Sopenharmony_ci				 var->green.offset) |
116962306a36Sopenharmony_ci				(blue >> (16 - var->blue.length));
117062306a36Sopenharmony_ci			((u32 *)(fbi->pseudo_palette))[regno] = pal;
117162306a36Sopenharmony_ci		}
117262306a36Sopenharmony_ci		break;
117362306a36Sopenharmony_ci	default:
117462306a36Sopenharmony_ci		BUG();
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci	return r;
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
118062306a36Sopenharmony_ci		u_int transp, struct fb_info *info)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	DBG("setcolreg\n");
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return _setcolreg(info, regno, red, green, blue, transp, 1);
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cistatic int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	int count, index, r;
119062306a36Sopenharmony_ci	u16 *red, *green, *blue, *transp;
119162306a36Sopenharmony_ci	u16 trans = 0xffff;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	DBG("setcmap\n");
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	red     = cmap->red;
119662306a36Sopenharmony_ci	green   = cmap->green;
119762306a36Sopenharmony_ci	blue    = cmap->blue;
119862306a36Sopenharmony_ci	transp  = cmap->transp;
119962306a36Sopenharmony_ci	index   = cmap->start;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	for (count = 0; count < cmap->len; count++) {
120262306a36Sopenharmony_ci		if (transp)
120362306a36Sopenharmony_ci			trans = *transp++;
120462306a36Sopenharmony_ci		r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
120562306a36Sopenharmony_ci				count == cmap->len - 1);
120662306a36Sopenharmony_ci		if (r != 0)
120762306a36Sopenharmony_ci			return r;
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	return 0;
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic int omapfb_blank(int blank, struct fb_info *fbi)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
121662306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
121762306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
121862306a36Sopenharmony_ci	struct omapfb_display_data *d;
121962306a36Sopenharmony_ci	int r = 0;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (!display)
122262306a36Sopenharmony_ci		return -EINVAL;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	omapfb_lock(fbdev);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	d = get_display_data(fbdev, display);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	switch (blank) {
122962306a36Sopenharmony_ci	case FB_BLANK_UNBLANK:
123062306a36Sopenharmony_ci		if (display->state == OMAP_DSS_DISPLAY_ACTIVE)
123162306a36Sopenharmony_ci			goto exit;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci		r = display->driver->enable(display);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
123662306a36Sopenharmony_ci				d->update_mode == OMAPFB_AUTO_UPDATE &&
123762306a36Sopenharmony_ci				!d->auto_update_work_enabled)
123862306a36Sopenharmony_ci			omapfb_start_auto_update(fbdev, display);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci		break;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	case FB_BLANK_NORMAL:
124362306a36Sopenharmony_ci		/* FB_BLANK_NORMAL could be implemented.
124462306a36Sopenharmony_ci		 * Needs DSS additions. */
124562306a36Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:
124662306a36Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:
124762306a36Sopenharmony_ci	case FB_BLANK_POWERDOWN:
124862306a36Sopenharmony_ci		if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
124962306a36Sopenharmony_ci			goto exit;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci		if (d->auto_update_work_enabled)
125262306a36Sopenharmony_ci			omapfb_stop_auto_update(fbdev, display);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci		display->driver->disable(display);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci		break;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	default:
125962306a36Sopenharmony_ci		r = -EINVAL;
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ciexit:
126362306a36Sopenharmony_ci	omapfb_unlock(fbdev);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	return r;
126662306a36Sopenharmony_ci}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci#if 0
126962306a36Sopenharmony_ci/* XXX fb_read and fb_write are needed for VRFB */
127062306a36Sopenharmony_cissize_t omapfb_write(struct fb_info *info, const char __user *buf,
127162306a36Sopenharmony_ci		size_t count, loff_t *ppos)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
127462306a36Sopenharmony_ci	/* XXX needed for VRFB */
127562306a36Sopenharmony_ci	return count;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci#endif
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cistatic const struct fb_ops omapfb_ops = {
128062306a36Sopenharmony_ci	.owner          = THIS_MODULE,
128162306a36Sopenharmony_ci	.fb_open        = omapfb_open,
128262306a36Sopenharmony_ci	.fb_release     = omapfb_release,
128362306a36Sopenharmony_ci	.fb_fillrect    = cfb_fillrect,
128462306a36Sopenharmony_ci	.fb_copyarea    = cfb_copyarea,
128562306a36Sopenharmony_ci	.fb_imageblit   = cfb_imageblit,
128662306a36Sopenharmony_ci	.fb_blank       = omapfb_blank,
128762306a36Sopenharmony_ci	.fb_ioctl       = omapfb_ioctl,
128862306a36Sopenharmony_ci	.fb_check_var   = omapfb_check_var,
128962306a36Sopenharmony_ci	.fb_set_par     = omapfb_set_par,
129062306a36Sopenharmony_ci	.fb_pan_display = omapfb_pan_display,
129162306a36Sopenharmony_ci	.fb_mmap	= omapfb_mmap,
129262306a36Sopenharmony_ci	.fb_setcolreg	= omapfb_setcolreg,
129362306a36Sopenharmony_ci	.fb_setcmap	= omapfb_setcmap,
129462306a36Sopenharmony_ci	/*.fb_write	= omapfb_write,*/
129562306a36Sopenharmony_ci};
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_cistatic void omapfb_free_fbmem(struct fb_info *fbi)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
130062306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
130162306a36Sopenharmony_ci	struct omapfb2_mem_region *rg;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	rg = ofbi->region;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	if (rg->token == NULL)
130662306a36Sopenharmony_ci		return;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	WARN_ON(atomic_read(&rg->map_count));
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
131162306a36Sopenharmony_ci		/* unmap the 0 angle rotation */
131262306a36Sopenharmony_ci		if (rg->vrfb.vaddr[0]) {
131362306a36Sopenharmony_ci			iounmap(rg->vrfb.vaddr[0]);
131462306a36Sopenharmony_ci			rg->vrfb.vaddr[0] = NULL;
131562306a36Sopenharmony_ci		}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci		omap_vrfb_release_ctx(&rg->vrfb);
131862306a36Sopenharmony_ci	}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle,
132162306a36Sopenharmony_ci			rg->attrs);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	rg->token = NULL;
132462306a36Sopenharmony_ci	rg->vaddr = NULL;
132562306a36Sopenharmony_ci	rg->paddr = 0;
132662306a36Sopenharmony_ci	rg->alloc = 0;
132762306a36Sopenharmony_ci	rg->size = 0;
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cistatic void clear_fb_info(struct fb_info *fbi)
133162306a36Sopenharmony_ci{
133262306a36Sopenharmony_ci	memset(&fbi->var, 0, sizeof(fbi->var));
133362306a36Sopenharmony_ci	memset(&fbi->fix, 0, sizeof(fbi->fix));
133462306a36Sopenharmony_ci	strscpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	int i;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	DBG("free all fbmem\n");
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
134462306a36Sopenharmony_ci		struct fb_info *fbi = fbdev->fbs[i];
134562306a36Sopenharmony_ci		omapfb_free_fbmem(fbi);
134662306a36Sopenharmony_ci		clear_fb_info(fbi);
134762306a36Sopenharmony_ci	}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	return 0;
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
135362306a36Sopenharmony_ci		unsigned long paddr)
135462306a36Sopenharmony_ci{
135562306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
135662306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
135762306a36Sopenharmony_ci	struct omapfb2_mem_region *rg;
135862306a36Sopenharmony_ci	void *token;
135962306a36Sopenharmony_ci	unsigned long attrs;
136062306a36Sopenharmony_ci	dma_addr_t dma_handle;
136162306a36Sopenharmony_ci	int r;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	rg = ofbi->region;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	rg->paddr = 0;
136662306a36Sopenharmony_ci	rg->vaddr = NULL;
136762306a36Sopenharmony_ci	memset(&rg->vrfb, 0, sizeof rg->vrfb);
136862306a36Sopenharmony_ci	rg->size = 0;
136962306a36Sopenharmony_ci	rg->type = 0;
137062306a36Sopenharmony_ci	rg->alloc = false;
137162306a36Sopenharmony_ci	rg->map = false;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	size = PAGE_ALIGN(size);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	attrs = DMA_ATTR_WRITE_COMBINE;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
137862306a36Sopenharmony_ci		attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	token = dma_alloc_attrs(fbdev->dev, size, &dma_handle,
138362306a36Sopenharmony_ci			GFP_KERNEL, attrs);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (token == NULL) {
138662306a36Sopenharmony_ci		dev_err(fbdev->dev, "failed to allocate framebuffer\n");
138762306a36Sopenharmony_ci		return -ENOMEM;
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	DBG("allocated VRAM paddr %lx, vaddr %p\n",
139162306a36Sopenharmony_ci			(unsigned long)dma_handle, token);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
139462306a36Sopenharmony_ci		r = omap_vrfb_request_ctx(&rg->vrfb);
139562306a36Sopenharmony_ci		if (r) {
139662306a36Sopenharmony_ci			dma_free_attrs(fbdev->dev, size, token, dma_handle,
139762306a36Sopenharmony_ci					attrs);
139862306a36Sopenharmony_ci			dev_err(fbdev->dev, "vrfb create ctx failed\n");
139962306a36Sopenharmony_ci			return r;
140062306a36Sopenharmony_ci		}
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	rg->attrs = attrs;
140462306a36Sopenharmony_ci	rg->token = token;
140562306a36Sopenharmony_ci	rg->dma_handle = dma_handle;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	rg->paddr = (unsigned long)dma_handle;
140862306a36Sopenharmony_ci	rg->vaddr = (void __iomem *)token;
140962306a36Sopenharmony_ci	rg->size = size;
141062306a36Sopenharmony_ci	rg->alloc = 1;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	return 0;
141362306a36Sopenharmony_ci}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci/* allocate fbmem using display resolution as reference */
141662306a36Sopenharmony_cistatic int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
141762306a36Sopenharmony_ci		unsigned long paddr)
141862306a36Sopenharmony_ci{
141962306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
142062306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
142162306a36Sopenharmony_ci	struct omap_dss_device *display;
142262306a36Sopenharmony_ci	int bytespp;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	display =  fb2display(fbi);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	if (!display)
142762306a36Sopenharmony_ci		return 0;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	switch (omapfb_get_recommended_bpp(fbdev, display)) {
143062306a36Sopenharmony_ci	case 16:
143162306a36Sopenharmony_ci		bytespp = 2;
143262306a36Sopenharmony_ci		break;
143362306a36Sopenharmony_ci	case 24:
143462306a36Sopenharmony_ci		bytespp = 4;
143562306a36Sopenharmony_ci		break;
143662306a36Sopenharmony_ci	default:
143762306a36Sopenharmony_ci		bytespp = 4;
143862306a36Sopenharmony_ci		break;
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (!size) {
144262306a36Sopenharmony_ci		u16 w, h;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci		display->driver->get_resolution(display, &w, &h);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci		if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
144762306a36Sopenharmony_ci			size = max(omap_vrfb_min_phys_size(w, h, bytespp),
144862306a36Sopenharmony_ci					omap_vrfb_min_phys_size(h, w, bytespp));
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci			DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
145162306a36Sopenharmony_ci					w * h * bytespp, size);
145262306a36Sopenharmony_ci		} else {
145362306a36Sopenharmony_ci			size = w * h * bytespp;
145462306a36Sopenharmony_ci		}
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if (!size)
145862306a36Sopenharmony_ci		return 0;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	return omapfb_alloc_fbmem(fbi, size, paddr);
146162306a36Sopenharmony_ci}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_cistatic int omapfb_parse_vram_param(const char *param, int max_entries,
146462306a36Sopenharmony_ci		unsigned long *sizes, unsigned long *paddrs)
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	unsigned int fbnum;
146762306a36Sopenharmony_ci	unsigned long size;
146862306a36Sopenharmony_ci	unsigned long paddr = 0;
146962306a36Sopenharmony_ci	char *p, *start;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	start = (char *)param;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	while (1) {
147462306a36Sopenharmony_ci		p = start;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci		fbnum = simple_strtoul(p, &p, 10);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci		if (p == start)
147962306a36Sopenharmony_ci			return -EINVAL;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci		if (*p != ':')
148262306a36Sopenharmony_ci			return -EINVAL;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci		if (fbnum >= max_entries)
148562306a36Sopenharmony_ci			return -EINVAL;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci		size = memparse(p + 1, &p);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		if (!size)
149062306a36Sopenharmony_ci			return -EINVAL;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci		paddr = 0;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci		if (*p == '@') {
149562306a36Sopenharmony_ci			paddr = simple_strtoul(p + 1, &p, 16);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci			if (!paddr)
149862306a36Sopenharmony_ci				return -EINVAL;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci		WARN_ONCE(paddr,
150362306a36Sopenharmony_ci			"reserving memory at predefined address not supported\n");
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci		paddrs[fbnum] = paddr;
150662306a36Sopenharmony_ci		sizes[fbnum] = size;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci		if (*p == 0)
150962306a36Sopenharmony_ci			break;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci		if (*p != ',')
151262306a36Sopenharmony_ci			return -EINVAL;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		++p;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		start = p;
151762306a36Sopenharmony_ci	}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	return 0;
152062306a36Sopenharmony_ci}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_cistatic int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
152362306a36Sopenharmony_ci{
152462306a36Sopenharmony_ci	int i, r;
152562306a36Sopenharmony_ci	unsigned long vram_sizes[10];
152662306a36Sopenharmony_ci	unsigned long vram_paddrs[10];
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	memset(&vram_sizes, 0, sizeof(vram_sizes));
152962306a36Sopenharmony_ci	memset(&vram_paddrs, 0, sizeof(vram_paddrs));
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (def_vram &&	omapfb_parse_vram_param(def_vram, 10,
153262306a36Sopenharmony_ci				vram_sizes, vram_paddrs)) {
153362306a36Sopenharmony_ci		dev_err(fbdev->dev, "failed to parse vram parameter\n");
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci		memset(&vram_sizes, 0, sizeof(vram_sizes));
153662306a36Sopenharmony_ci		memset(&vram_paddrs, 0, sizeof(vram_paddrs));
153762306a36Sopenharmony_ci	}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
154062306a36Sopenharmony_ci		/* allocate memory automatically only for fb0, or if
154162306a36Sopenharmony_ci		 * excplicitly defined with vram or plat data option */
154262306a36Sopenharmony_ci		if (i == 0 || vram_sizes[i] != 0) {
154362306a36Sopenharmony_ci			r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
154462306a36Sopenharmony_ci					vram_sizes[i], vram_paddrs[i]);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci			if (r)
154762306a36Sopenharmony_ci				return r;
154862306a36Sopenharmony_ci		}
154962306a36Sopenharmony_ci	}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
155262306a36Sopenharmony_ci		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
155362306a36Sopenharmony_ci		struct omapfb2_mem_region *rg;
155462306a36Sopenharmony_ci		rg = ofbi->region;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci		DBG("region%d phys %08x virt %p size=%lu\n",
155762306a36Sopenharmony_ci				i,
155862306a36Sopenharmony_ci				rg->paddr,
155962306a36Sopenharmony_ci				rg->vaddr,
156062306a36Sopenharmony_ci				rg->size);
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	return 0;
156462306a36Sopenharmony_ci}
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_cistatic void omapfb_clear_fb(struct fb_info *fbi)
156762306a36Sopenharmony_ci{
156862306a36Sopenharmony_ci	const struct fb_fillrect rect = {
156962306a36Sopenharmony_ci		.dx = 0,
157062306a36Sopenharmony_ci		.dy = 0,
157162306a36Sopenharmony_ci		.width = fbi->var.xres_virtual,
157262306a36Sopenharmony_ci		.height = fbi->var.yres_virtual,
157362306a36Sopenharmony_ci		.color = 0,
157462306a36Sopenharmony_ci		.rop = ROP_COPY,
157562306a36Sopenharmony_ci	};
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	cfb_fillrect(fbi, &rect);
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ciint omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
158362306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
158462306a36Sopenharmony_ci	struct omapfb2_mem_region *rg = ofbi->region;
158562306a36Sopenharmony_ci	unsigned long old_size = rg->size;
158662306a36Sopenharmony_ci	unsigned long old_paddr = rg->paddr;
158762306a36Sopenharmony_ci	int old_type = rg->type;
158862306a36Sopenharmony_ci	int r;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	if (type != OMAPFB_MEMTYPE_SDRAM)
159162306a36Sopenharmony_ci		return -EINVAL;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	size = PAGE_ALIGN(size);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	if (old_size == size && old_type == type)
159662306a36Sopenharmony_ci		return 0;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	omapfb_free_fbmem(fbi);
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	if (size == 0) {
160162306a36Sopenharmony_ci		clear_fb_info(fbi);
160262306a36Sopenharmony_ci		return 0;
160362306a36Sopenharmony_ci	}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	r = omapfb_alloc_fbmem(fbi, size, 0);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	if (r) {
160862306a36Sopenharmony_ci		if (old_size)
160962306a36Sopenharmony_ci			omapfb_alloc_fbmem(fbi, old_size, old_paddr);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci		if (rg->size == 0)
161262306a36Sopenharmony_ci			clear_fb_info(fbi);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci		return r;
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (old_size == size)
161862306a36Sopenharmony_ci		return 0;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (old_size == 0) {
162162306a36Sopenharmony_ci		DBG("initializing fb %d\n", ofbi->id);
162262306a36Sopenharmony_ci		r = omapfb_fb_init(fbdev, fbi);
162362306a36Sopenharmony_ci		if (r) {
162462306a36Sopenharmony_ci			DBG("omapfb_fb_init failed\n");
162562306a36Sopenharmony_ci			goto err;
162662306a36Sopenharmony_ci		}
162762306a36Sopenharmony_ci		r = omapfb_apply_changes(fbi, 1);
162862306a36Sopenharmony_ci		if (r) {
162962306a36Sopenharmony_ci			DBG("omapfb_apply_changes failed\n");
163062306a36Sopenharmony_ci			goto err;
163162306a36Sopenharmony_ci		}
163262306a36Sopenharmony_ci	} else {
163362306a36Sopenharmony_ci		struct fb_var_screeninfo new_var;
163462306a36Sopenharmony_ci		memcpy(&new_var, &fbi->var, sizeof(new_var));
163562306a36Sopenharmony_ci		r = check_fb_var(fbi, &new_var);
163662306a36Sopenharmony_ci		if (r)
163762306a36Sopenharmony_ci			goto err;
163862306a36Sopenharmony_ci		memcpy(&fbi->var, &new_var, sizeof(fbi->var));
163962306a36Sopenharmony_ci		set_fb_fix(fbi);
164062306a36Sopenharmony_ci		r = setup_vrfb_rotation(fbi);
164162306a36Sopenharmony_ci		if (r)
164262306a36Sopenharmony_ci			goto err;
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	omapfb_clear_fb(fbi);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	return 0;
164862306a36Sopenharmony_cierr:
164962306a36Sopenharmony_ci	omapfb_free_fbmem(fbi);
165062306a36Sopenharmony_ci	clear_fb_info(fbi);
165162306a36Sopenharmony_ci	return r;
165262306a36Sopenharmony_ci}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_cistatic void omapfb_auto_update_work(struct work_struct *work)
165562306a36Sopenharmony_ci{
165662306a36Sopenharmony_ci	struct omap_dss_device *dssdev;
165762306a36Sopenharmony_ci	struct omap_dss_driver *dssdrv;
165862306a36Sopenharmony_ci	struct omapfb_display_data *d;
165962306a36Sopenharmony_ci	u16 w, h;
166062306a36Sopenharmony_ci	unsigned int freq;
166162306a36Sopenharmony_ci	struct omapfb2_device *fbdev;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	d = container_of(work, struct omapfb_display_data,
166462306a36Sopenharmony_ci			auto_update_work.work);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	dssdev = d->dssdev;
166762306a36Sopenharmony_ci	dssdrv = dssdev->driver;
166862306a36Sopenharmony_ci	fbdev = d->fbdev;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	if (!dssdrv || !dssdrv->update)
167162306a36Sopenharmony_ci		return;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	if (dssdrv->sync)
167462306a36Sopenharmony_ci		dssdrv->sync(dssdev);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	dssdrv->get_resolution(dssdev, &w, &h);
167762306a36Sopenharmony_ci	dssdrv->update(dssdev, 0, 0, w, h);
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	freq = auto_update_freq;
168062306a36Sopenharmony_ci	if (freq == 0)
168162306a36Sopenharmony_ci		freq = 20;
168262306a36Sopenharmony_ci	queue_delayed_work(fbdev->auto_update_wq,
168362306a36Sopenharmony_ci			&d->auto_update_work, HZ / freq);
168462306a36Sopenharmony_ci}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_civoid omapfb_start_auto_update(struct omapfb2_device *fbdev,
168762306a36Sopenharmony_ci		struct omap_dss_device *display)
168862306a36Sopenharmony_ci{
168962306a36Sopenharmony_ci	struct omapfb_display_data *d;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	if (fbdev->auto_update_wq == NULL) {
169262306a36Sopenharmony_ci		struct workqueue_struct *wq;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci		wq = create_singlethread_workqueue("omapfb_auto_update");
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci		if (wq == NULL) {
169762306a36Sopenharmony_ci			dev_err(fbdev->dev, "Failed to create workqueue for "
169862306a36Sopenharmony_ci					"auto-update\n");
169962306a36Sopenharmony_ci			return;
170062306a36Sopenharmony_ci		}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci		fbdev->auto_update_wq = wq;
170362306a36Sopenharmony_ci	}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	d = get_display_data(fbdev, display);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	d->auto_update_work_enabled = true;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	omapfb_auto_update_work(&d->auto_update_work.work);
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_civoid omapfb_stop_auto_update(struct omapfb2_device *fbdev,
171562306a36Sopenharmony_ci		struct omap_dss_device *display)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci	struct omapfb_display_data *d;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	d = get_display_data(fbdev, display);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	cancel_delayed_work_sync(&d->auto_update_work);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	d->auto_update_work_enabled = false;
172462306a36Sopenharmony_ci}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci/* initialize fb_info, var, fix to something sane based on the display */
172762306a36Sopenharmony_cistatic int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
172862306a36Sopenharmony_ci{
172962306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &fbi->var;
173062306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
173162306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
173262306a36Sopenharmony_ci	int r = 0;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	fbi->fbops = &omapfb_ops;
173562306a36Sopenharmony_ci	fbi->pseudo_palette = fbdev->pseudo_palette;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	if (ofbi->region->size == 0) {
173862306a36Sopenharmony_ci		clear_fb_info(fbi);
173962306a36Sopenharmony_ci		return 0;
174062306a36Sopenharmony_ci	}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	var->nonstd = 0;
174362306a36Sopenharmony_ci	var->bits_per_pixel = 0;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	var->rotate = def_rotate;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	if (display) {
174862306a36Sopenharmony_ci		u16 w, h;
174962306a36Sopenharmony_ci		int rotation = (var->rotate + ofbi->rotation[0]) % 4;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci		display->driver->get_resolution(display, &w, &h);
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci		if (rotation == FB_ROTATE_CW ||
175462306a36Sopenharmony_ci				rotation == FB_ROTATE_CCW) {
175562306a36Sopenharmony_ci			var->xres = h;
175662306a36Sopenharmony_ci			var->yres = w;
175762306a36Sopenharmony_ci		} else {
175862306a36Sopenharmony_ci			var->xres = w;
175962306a36Sopenharmony_ci			var->yres = h;
176062306a36Sopenharmony_ci		}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci		var->xres_virtual = var->xres;
176362306a36Sopenharmony_ci		var->yres_virtual = var->yres;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci		if (!var->bits_per_pixel) {
176662306a36Sopenharmony_ci			switch (omapfb_get_recommended_bpp(fbdev, display)) {
176762306a36Sopenharmony_ci			case 16:
176862306a36Sopenharmony_ci				var->bits_per_pixel = 16;
176962306a36Sopenharmony_ci				break;
177062306a36Sopenharmony_ci			case 24:
177162306a36Sopenharmony_ci				var->bits_per_pixel = 32;
177262306a36Sopenharmony_ci				break;
177362306a36Sopenharmony_ci			default:
177462306a36Sopenharmony_ci				dev_err(fbdev->dev, "illegal display "
177562306a36Sopenharmony_ci						"bpp\n");
177662306a36Sopenharmony_ci				return -EINVAL;
177762306a36Sopenharmony_ci			}
177862306a36Sopenharmony_ci		}
177962306a36Sopenharmony_ci	} else {
178062306a36Sopenharmony_ci		/* if there's no display, let's just guess some basic values */
178162306a36Sopenharmony_ci		var->xres = 320;
178262306a36Sopenharmony_ci		var->yres = 240;
178362306a36Sopenharmony_ci		var->xres_virtual = var->xres;
178462306a36Sopenharmony_ci		var->yres_virtual = var->yres;
178562306a36Sopenharmony_ci		if (!var->bits_per_pixel)
178662306a36Sopenharmony_ci			var->bits_per_pixel = 16;
178762306a36Sopenharmony_ci	}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	r = check_fb_var(fbi, var);
179062306a36Sopenharmony_ci	if (r)
179162306a36Sopenharmony_ci		goto err;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	set_fb_fix(fbi);
179462306a36Sopenharmony_ci	r = setup_vrfb_rotation(fbi);
179562306a36Sopenharmony_ci	if (r)
179662306a36Sopenharmony_ci		goto err;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	r = fb_alloc_cmap(&fbi->cmap, 256, 0);
179962306a36Sopenharmony_ci	if (r)
180062306a36Sopenharmony_ci		dev_err(fbdev->dev, "unable to allocate color map memory\n");
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_cierr:
180362306a36Sopenharmony_ci	return r;
180462306a36Sopenharmony_ci}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_cistatic void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
180762306a36Sopenharmony_ci{
180862306a36Sopenharmony_ci	fb_dealloc_cmap(&fbi->cmap);
180962306a36Sopenharmony_ci}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_cistatic void omapfb_free_resources(struct omapfb2_device *fbdev)
181362306a36Sopenharmony_ci{
181462306a36Sopenharmony_ci	int i;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	DBG("free_resources\n");
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	if (fbdev == NULL)
181962306a36Sopenharmony_ci		return;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_overlays; i++) {
182262306a36Sopenharmony_ci		struct omap_overlay *ovl = fbdev->overlays[i];
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci		ovl->disable(ovl);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci		if (ovl->manager)
182762306a36Sopenharmony_ci			ovl->unset_manager(ovl);
182862306a36Sopenharmony_ci	}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++)
183162306a36Sopenharmony_ci		unregister_framebuffer(fbdev->fbs[i]);
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	/* free the reserved fbmem */
183462306a36Sopenharmony_ci	omapfb_free_all_fbmem(fbdev);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
183762306a36Sopenharmony_ci		fbinfo_cleanup(fbdev, fbdev->fbs[i]);
183862306a36Sopenharmony_ci		framebuffer_release(fbdev->fbs[i]);
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_displays; i++) {
184262306a36Sopenharmony_ci		struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci		if (fbdev->displays[i].auto_update_work_enabled)
184562306a36Sopenharmony_ci			omapfb_stop_auto_update(fbdev, dssdev);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci		if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
184862306a36Sopenharmony_ci			dssdev->driver->disable(dssdev);
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci		dssdev->driver->disconnect(dssdev);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci		omap_dss_put_device(dssdev);
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	if (fbdev->auto_update_wq != NULL) {
185662306a36Sopenharmony_ci		destroy_workqueue(fbdev->auto_update_wq);
185762306a36Sopenharmony_ci		fbdev->auto_update_wq = NULL;
185862306a36Sopenharmony_ci	}
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	dev_set_drvdata(fbdev->dev, NULL);
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	int r, i;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	fbdev->num_fbs = 0;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	DBG("create %d framebuffers\n",	CONFIG_FB_OMAP2_NUM_FBS);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	/* allocate fb_infos */
187262306a36Sopenharmony_ci	for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
187362306a36Sopenharmony_ci		struct fb_info *fbi;
187462306a36Sopenharmony_ci		struct omapfb_info *ofbi;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci		fbi = framebuffer_alloc(sizeof(struct omapfb_info),
187762306a36Sopenharmony_ci				fbdev->dev);
187862306a36Sopenharmony_ci		if (!fbi)
187962306a36Sopenharmony_ci			return -ENOMEM;
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci		clear_fb_info(fbi);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci		fbdev->fbs[i] = fbi;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci		ofbi = FB2OFB(fbi);
188662306a36Sopenharmony_ci		ofbi->fbdev = fbdev;
188762306a36Sopenharmony_ci		ofbi->id = i;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci		ofbi->region = &fbdev->regions[i];
189062306a36Sopenharmony_ci		ofbi->region->id = i;
189162306a36Sopenharmony_ci		init_rwsem(&ofbi->region->lock);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci		/* assign these early, so that fb alloc can use them */
189462306a36Sopenharmony_ci		ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
189562306a36Sopenharmony_ci			OMAP_DSS_ROT_DMA;
189662306a36Sopenharmony_ci		ofbi->mirror = def_mirror;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci		fbdev->num_fbs++;
189962306a36Sopenharmony_ci	}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	DBG("fb_infos allocated\n");
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	/* assign overlays for the fbs */
190462306a36Sopenharmony_ci	for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
190562306a36Sopenharmony_ci		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci		ofbi->overlays[0] = fbdev->overlays[i];
190862306a36Sopenharmony_ci		ofbi->num_overlays = 1;
190962306a36Sopenharmony_ci	}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	/* allocate fb memories */
191262306a36Sopenharmony_ci	r = omapfb_allocate_all_fbs(fbdev);
191362306a36Sopenharmony_ci	if (r) {
191462306a36Sopenharmony_ci		dev_err(fbdev->dev, "failed to allocate fbmem\n");
191562306a36Sopenharmony_ci		return r;
191662306a36Sopenharmony_ci	}
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	DBG("fbmems allocated\n");
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	/* setup fb_infos */
192162306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
192262306a36Sopenharmony_ci		struct fb_info *fbi = fbdev->fbs[i];
192362306a36Sopenharmony_ci		struct omapfb_info *ofbi = FB2OFB(fbi);
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci		omapfb_get_mem_region(ofbi->region);
192662306a36Sopenharmony_ci		r = omapfb_fb_init(fbdev, fbi);
192762306a36Sopenharmony_ci		omapfb_put_mem_region(ofbi->region);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci		if (r) {
193062306a36Sopenharmony_ci			dev_err(fbdev->dev, "failed to setup fb_info\n");
193162306a36Sopenharmony_ci			return r;
193262306a36Sopenharmony_ci		}
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
193662306a36Sopenharmony_ci		struct fb_info *fbi = fbdev->fbs[i];
193762306a36Sopenharmony_ci		struct omapfb_info *ofbi = FB2OFB(fbi);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci		if (ofbi->region->size == 0)
194062306a36Sopenharmony_ci			continue;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci		omapfb_clear_fb(fbi);
194362306a36Sopenharmony_ci	}
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	DBG("fb_infos initialized\n");
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
194862306a36Sopenharmony_ci		r = register_framebuffer(fbdev->fbs[i]);
194962306a36Sopenharmony_ci		if (r != 0) {
195062306a36Sopenharmony_ci			dev_err(fbdev->dev,
195162306a36Sopenharmony_ci				"registering framebuffer %d failed\n", i);
195262306a36Sopenharmony_ci			return r;
195362306a36Sopenharmony_ci		}
195462306a36Sopenharmony_ci	}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	DBG("framebuffers registered\n");
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
195962306a36Sopenharmony_ci		struct fb_info *fbi = fbdev->fbs[i];
196062306a36Sopenharmony_ci		struct omapfb_info *ofbi = FB2OFB(fbi);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci		omapfb_get_mem_region(ofbi->region);
196362306a36Sopenharmony_ci		r = omapfb_apply_changes(fbi, 1);
196462306a36Sopenharmony_ci		omapfb_put_mem_region(ofbi->region);
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci		if (r) {
196762306a36Sopenharmony_ci			dev_err(fbdev->dev, "failed to change mode\n");
196862306a36Sopenharmony_ci			return r;
196962306a36Sopenharmony_ci		}
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	/* Enable fb0 */
197362306a36Sopenharmony_ci	if (fbdev->num_fbs > 0) {
197462306a36Sopenharmony_ci		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci		if (ofbi->num_overlays > 0) {
197762306a36Sopenharmony_ci			struct omap_overlay *ovl = ofbi->overlays[0];
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci			ovl->manager->apply(ovl->manager);
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci			r = omapfb_overlay_enable(ovl, 1);
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci			if (r) {
198462306a36Sopenharmony_ci				dev_err(fbdev->dev,
198562306a36Sopenharmony_ci						"failed to enable overlay\n");
198662306a36Sopenharmony_ci				return r;
198762306a36Sopenharmony_ci			}
198862306a36Sopenharmony_ci		}
198962306a36Sopenharmony_ci	}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	DBG("create_framebuffers done\n");
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	return 0;
199462306a36Sopenharmony_ci}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_cistatic int omapfb_mode_to_timings(const char *mode_str,
199762306a36Sopenharmony_ci		struct omap_dss_device *display,
199862306a36Sopenharmony_ci		struct omap_video_timings *timings, u8 *bpp)
199962306a36Sopenharmony_ci{
200062306a36Sopenharmony_ci	struct fb_info *fbi;
200162306a36Sopenharmony_ci	struct fb_var_screeninfo *var;
200262306a36Sopenharmony_ci	struct fb_ops *fbops;
200362306a36Sopenharmony_ci	int r;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci#ifdef CONFIG_OMAP2_DSS_VENC
200662306a36Sopenharmony_ci	if (strcmp(mode_str, "pal") == 0) {
200762306a36Sopenharmony_ci		*timings = omap_dss_pal_timings;
200862306a36Sopenharmony_ci		*bpp = 24;
200962306a36Sopenharmony_ci		return 0;
201062306a36Sopenharmony_ci	} else if (strcmp(mode_str, "ntsc") == 0) {
201162306a36Sopenharmony_ci		*timings = omap_dss_ntsc_timings;
201262306a36Sopenharmony_ci		*bpp = 24;
201362306a36Sopenharmony_ci		return 0;
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci#endif
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	/* this is quite a hack, but I wanted to use the modedb and for
201862306a36Sopenharmony_ci	 * that we need fb_info and var, so we create dummy ones */
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	*bpp = 0;
202162306a36Sopenharmony_ci	fbi = NULL;
202262306a36Sopenharmony_ci	var = NULL;
202362306a36Sopenharmony_ci	fbops = NULL;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
202662306a36Sopenharmony_ci	if (fbi == NULL) {
202762306a36Sopenharmony_ci		r = -ENOMEM;
202862306a36Sopenharmony_ci		goto err;
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	var = kzalloc(sizeof(*var), GFP_KERNEL);
203262306a36Sopenharmony_ci	if (var == NULL) {
203362306a36Sopenharmony_ci		r = -ENOMEM;
203462306a36Sopenharmony_ci		goto err;
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
203862306a36Sopenharmony_ci	if (fbops == NULL) {
203962306a36Sopenharmony_ci		r = -ENOMEM;
204062306a36Sopenharmony_ci		goto err;
204162306a36Sopenharmony_ci	}
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	fbi->fbops = fbops;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
204662306a36Sopenharmony_ci	if (r == 0) {
204762306a36Sopenharmony_ci		r = -EINVAL;
204862306a36Sopenharmony_ci		goto err;
204962306a36Sopenharmony_ci	}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	if (display->driver->get_timings) {
205262306a36Sopenharmony_ci		display->driver->get_timings(display, timings);
205362306a36Sopenharmony_ci	} else {
205462306a36Sopenharmony_ci		timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
205562306a36Sopenharmony_ci		timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
205662306a36Sopenharmony_ci		timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
205762306a36Sopenharmony_ci	}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	timings->pixelclock = PICOS2KHZ(var->pixclock) * 1000;
206062306a36Sopenharmony_ci	timings->hbp = var->left_margin;
206162306a36Sopenharmony_ci	timings->hfp = var->right_margin;
206262306a36Sopenharmony_ci	timings->vbp = var->upper_margin;
206362306a36Sopenharmony_ci	timings->vfp = var->lower_margin;
206462306a36Sopenharmony_ci	timings->hsw = var->hsync_len;
206562306a36Sopenharmony_ci	timings->vsw = var->vsync_len;
206662306a36Sopenharmony_ci	timings->x_res = var->xres;
206762306a36Sopenharmony_ci	timings->y_res = var->yres;
206862306a36Sopenharmony_ci	timings->hsync_level = var->sync & FB_SYNC_HOR_HIGH_ACT ?
206962306a36Sopenharmony_ci				OMAPDSS_SIG_ACTIVE_HIGH :
207062306a36Sopenharmony_ci				OMAPDSS_SIG_ACTIVE_LOW;
207162306a36Sopenharmony_ci	timings->vsync_level = var->sync & FB_SYNC_VERT_HIGH_ACT ?
207262306a36Sopenharmony_ci				OMAPDSS_SIG_ACTIVE_HIGH :
207362306a36Sopenharmony_ci				OMAPDSS_SIG_ACTIVE_LOW;
207462306a36Sopenharmony_ci	timings->interlace = var->vmode & FB_VMODE_INTERLACED;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	switch (var->bits_per_pixel) {
207762306a36Sopenharmony_ci	case 16:
207862306a36Sopenharmony_ci		*bpp = 16;
207962306a36Sopenharmony_ci		break;
208062306a36Sopenharmony_ci	case 24:
208162306a36Sopenharmony_ci	case 32:
208262306a36Sopenharmony_ci	default:
208362306a36Sopenharmony_ci		*bpp = 24;
208462306a36Sopenharmony_ci		break;
208562306a36Sopenharmony_ci	}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	r = 0;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_cierr:
209062306a36Sopenharmony_ci	kfree(fbi);
209162306a36Sopenharmony_ci	kfree(var);
209262306a36Sopenharmony_ci	kfree(fbops);
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	return r;
209562306a36Sopenharmony_ci}
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_cistatic int omapfb_set_def_mode(struct omapfb2_device *fbdev,
209862306a36Sopenharmony_ci		struct omap_dss_device *display, char *mode_str)
209962306a36Sopenharmony_ci{
210062306a36Sopenharmony_ci	int r;
210162306a36Sopenharmony_ci	u8 bpp;
210262306a36Sopenharmony_ci	struct omap_video_timings timings, temp_timings;
210362306a36Sopenharmony_ci	struct omapfb_display_data *d;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	r = omapfb_mode_to_timings(mode_str, display, &timings, &bpp);
210662306a36Sopenharmony_ci	if (r)
210762306a36Sopenharmony_ci		return r;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	d = get_display_data(fbdev, display);
211062306a36Sopenharmony_ci	d->bpp_override = bpp;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	if (display->driver->check_timings) {
211362306a36Sopenharmony_ci		r = display->driver->check_timings(display, &timings);
211462306a36Sopenharmony_ci		if (r)
211562306a36Sopenharmony_ci			return r;
211662306a36Sopenharmony_ci	} else {
211762306a36Sopenharmony_ci		/* If check_timings is not present compare xres and yres */
211862306a36Sopenharmony_ci		if (display->driver->get_timings) {
211962306a36Sopenharmony_ci			display->driver->get_timings(display, &temp_timings);
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci			if (temp_timings.x_res != timings.x_res ||
212262306a36Sopenharmony_ci				temp_timings.y_res != timings.y_res)
212362306a36Sopenharmony_ci				return -EINVAL;
212462306a36Sopenharmony_ci		}
212562306a36Sopenharmony_ci	}
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	if (display->driver->set_timings)
212862306a36Sopenharmony_ci			display->driver->set_timings(display, &timings);
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	return 0;
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_cistatic int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
213462306a36Sopenharmony_ci		struct omap_dss_device *dssdev)
213562306a36Sopenharmony_ci{
213662306a36Sopenharmony_ci	struct omapfb_display_data *d;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	d = get_display_data(fbdev, dssdev);
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	if (d->bpp_override != 0)
214362306a36Sopenharmony_ci		return d->bpp_override;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	return dssdev->driver->get_recommended_bpp(dssdev);
214662306a36Sopenharmony_ci}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_cistatic int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
214962306a36Sopenharmony_ci{
215062306a36Sopenharmony_ci	char *str, *options, *this_opt;
215162306a36Sopenharmony_ci	int r = 0;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	str = kstrdup(def_mode, GFP_KERNEL);
215462306a36Sopenharmony_ci	if (!str)
215562306a36Sopenharmony_ci		return -ENOMEM;
215662306a36Sopenharmony_ci	options = str;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	while (!r && (this_opt = strsep(&options, ",")) != NULL) {
215962306a36Sopenharmony_ci		char *p, *display_str, *mode_str;
216062306a36Sopenharmony_ci		struct omap_dss_device *display;
216162306a36Sopenharmony_ci		int i;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci		p = strchr(this_opt, ':');
216462306a36Sopenharmony_ci		if (!p) {
216562306a36Sopenharmony_ci			r = -EINVAL;
216662306a36Sopenharmony_ci			break;
216762306a36Sopenharmony_ci		}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci		*p = 0;
217062306a36Sopenharmony_ci		display_str = this_opt;
217162306a36Sopenharmony_ci		mode_str = p + 1;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci		display = NULL;
217462306a36Sopenharmony_ci		for (i = 0; i < fbdev->num_displays; ++i) {
217562306a36Sopenharmony_ci			if (strcmp(fbdev->displays[i].dssdev->name,
217662306a36Sopenharmony_ci						display_str) == 0) {
217762306a36Sopenharmony_ci				display = fbdev->displays[i].dssdev;
217862306a36Sopenharmony_ci				break;
217962306a36Sopenharmony_ci			}
218062306a36Sopenharmony_ci		}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci		if (!display) {
218362306a36Sopenharmony_ci			r = -EINVAL;
218462306a36Sopenharmony_ci			break;
218562306a36Sopenharmony_ci		}
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci		r = omapfb_set_def_mode(fbdev, display, mode_str);
218862306a36Sopenharmony_ci		if (r)
218962306a36Sopenharmony_ci			break;
219062306a36Sopenharmony_ci	}
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	kfree(str);
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	return r;
219562306a36Sopenharmony_ci}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_cistatic void fb_videomode_to_omap_timings(struct fb_videomode *m,
219862306a36Sopenharmony_ci		struct omap_dss_device *display,
219962306a36Sopenharmony_ci		struct omap_video_timings *t)
220062306a36Sopenharmony_ci{
220162306a36Sopenharmony_ci	if (display->driver->get_timings) {
220262306a36Sopenharmony_ci		display->driver->get_timings(display, t);
220362306a36Sopenharmony_ci	} else {
220462306a36Sopenharmony_ci		t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
220562306a36Sopenharmony_ci		t->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
220662306a36Sopenharmony_ci		t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
220762306a36Sopenharmony_ci	}
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	t->x_res = m->xres;
221062306a36Sopenharmony_ci	t->y_res = m->yres;
221162306a36Sopenharmony_ci	t->pixelclock = PICOS2KHZ(m->pixclock) * 1000;
221262306a36Sopenharmony_ci	t->hsw = m->hsync_len;
221362306a36Sopenharmony_ci	t->hfp = m->right_margin;
221462306a36Sopenharmony_ci	t->hbp = m->left_margin;
221562306a36Sopenharmony_ci	t->vsw = m->vsync_len;
221662306a36Sopenharmony_ci	t->vfp = m->lower_margin;
221762306a36Sopenharmony_ci	t->vbp = m->upper_margin;
221862306a36Sopenharmony_ci	t->hsync_level = m->sync & FB_SYNC_HOR_HIGH_ACT ?
221962306a36Sopenharmony_ci				OMAPDSS_SIG_ACTIVE_HIGH :
222062306a36Sopenharmony_ci				OMAPDSS_SIG_ACTIVE_LOW;
222162306a36Sopenharmony_ci	t->vsync_level = m->sync & FB_SYNC_VERT_HIGH_ACT ?
222262306a36Sopenharmony_ci				OMAPDSS_SIG_ACTIVE_HIGH :
222362306a36Sopenharmony_ci				OMAPDSS_SIG_ACTIVE_LOW;
222462306a36Sopenharmony_ci	t->interlace = m->vmode & FB_VMODE_INTERLACED;
222562306a36Sopenharmony_ci}
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_cistatic int omapfb_find_best_mode(struct omap_dss_device *display,
222862306a36Sopenharmony_ci		struct omap_video_timings *timings)
222962306a36Sopenharmony_ci{
223062306a36Sopenharmony_ci	struct fb_monspecs *specs;
223162306a36Sopenharmony_ci	u8 *edid;
223262306a36Sopenharmony_ci	int r, i, best_idx, len;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	if (!display->driver->read_edid)
223562306a36Sopenharmony_ci		return -ENODEV;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	len = 0x80 * 2;
223862306a36Sopenharmony_ci	edid = kmalloc(len, GFP_KERNEL);
223962306a36Sopenharmony_ci	if (edid == NULL)
224062306a36Sopenharmony_ci		return -ENOMEM;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	r = display->driver->read_edid(display, edid, len);
224362306a36Sopenharmony_ci	if (r < 0)
224462306a36Sopenharmony_ci		goto err1;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	specs = kzalloc(sizeof(*specs), GFP_KERNEL);
224762306a36Sopenharmony_ci	if (specs == NULL) {
224862306a36Sopenharmony_ci		r = -ENOMEM;
224962306a36Sopenharmony_ci		goto err1;
225062306a36Sopenharmony_ci	}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	fb_edid_to_monspecs(edid, specs);
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	best_idx = -1;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	for (i = 0; i < specs->modedb_len; ++i) {
225762306a36Sopenharmony_ci		struct fb_videomode *m;
225862306a36Sopenharmony_ci		struct omap_video_timings t;
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci		m = &specs->modedb[i];
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci		if (m->pixclock == 0)
226362306a36Sopenharmony_ci			continue;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci		/* skip repeated pixel modes */
226662306a36Sopenharmony_ci		if (m->xres == 2880 || m->xres == 1440)
226762306a36Sopenharmony_ci			continue;
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci		if (m->vmode & FB_VMODE_INTERLACED ||
227062306a36Sopenharmony_ci				m->vmode & FB_VMODE_DOUBLE)
227162306a36Sopenharmony_ci			continue;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci		fb_videomode_to_omap_timings(m, display, &t);
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci		r = display->driver->check_timings(display, &t);
227662306a36Sopenharmony_ci		if (r == 0) {
227762306a36Sopenharmony_ci			best_idx = i;
227862306a36Sopenharmony_ci			break;
227962306a36Sopenharmony_ci		}
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	if (best_idx == -1) {
228362306a36Sopenharmony_ci		r = -ENOENT;
228462306a36Sopenharmony_ci		goto err2;
228562306a36Sopenharmony_ci	}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	fb_videomode_to_omap_timings(&specs->modedb[best_idx], display,
228862306a36Sopenharmony_ci		timings);
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	r = 0;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_cierr2:
229362306a36Sopenharmony_ci	fb_destroy_modedb(specs->modedb);
229462306a36Sopenharmony_ci	kfree(specs);
229562306a36Sopenharmony_cierr1:
229662306a36Sopenharmony_ci	kfree(edid);
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	return r;
229962306a36Sopenharmony_ci}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_cistatic int omapfb_init_display(struct omapfb2_device *fbdev,
230262306a36Sopenharmony_ci		struct omap_dss_device *dssdev)
230362306a36Sopenharmony_ci{
230462306a36Sopenharmony_ci	struct omap_dss_driver *dssdrv = dssdev->driver;
230562306a36Sopenharmony_ci	struct omapfb_display_data *d;
230662306a36Sopenharmony_ci	int r;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	r = dssdrv->enable(dssdev);
230962306a36Sopenharmony_ci	if (r) {
231062306a36Sopenharmony_ci		dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
231162306a36Sopenharmony_ci				dssdev->name);
231262306a36Sopenharmony_ci		return r;
231362306a36Sopenharmony_ci	}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	d = get_display_data(fbdev, dssdev);
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	d->fbdev = fbdev;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
232062306a36Sopenharmony_ci		u16 w, h;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci		if (auto_update) {
232362306a36Sopenharmony_ci			omapfb_start_auto_update(fbdev, dssdev);
232462306a36Sopenharmony_ci			d->update_mode = OMAPFB_AUTO_UPDATE;
232562306a36Sopenharmony_ci		} else {
232662306a36Sopenharmony_ci			d->update_mode = OMAPFB_MANUAL_UPDATE;
232762306a36Sopenharmony_ci		}
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci		if (dssdrv->enable_te) {
233062306a36Sopenharmony_ci			r = dssdrv->enable_te(dssdev, 1);
233162306a36Sopenharmony_ci			if (r) {
233262306a36Sopenharmony_ci				dev_err(fbdev->dev, "Failed to set TE\n");
233362306a36Sopenharmony_ci				return r;
233462306a36Sopenharmony_ci			}
233562306a36Sopenharmony_ci		}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci		dssdrv->get_resolution(dssdev, &w, &h);
233862306a36Sopenharmony_ci		r = dssdrv->update(dssdev, 0, 0, w, h);
233962306a36Sopenharmony_ci		if (r) {
234062306a36Sopenharmony_ci			dev_err(fbdev->dev,
234162306a36Sopenharmony_ci					"Failed to update display\n");
234262306a36Sopenharmony_ci			return r;
234362306a36Sopenharmony_ci		}
234462306a36Sopenharmony_ci	} else {
234562306a36Sopenharmony_ci		d->update_mode = OMAPFB_AUTO_UPDATE;
234662306a36Sopenharmony_ci	}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	return 0;
234962306a36Sopenharmony_ci}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_cistatic int omapfb_init_connections(struct omapfb2_device *fbdev,
235262306a36Sopenharmony_ci		struct omap_dss_device *def_dssdev)
235362306a36Sopenharmony_ci{
235462306a36Sopenharmony_ci	int i, r;
235562306a36Sopenharmony_ci	struct omap_overlay_manager *mgr;
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	r = def_dssdev->driver->connect(def_dssdev);
235862306a36Sopenharmony_ci	if (r) {
235962306a36Sopenharmony_ci		dev_err(fbdev->dev, "failed to connect default display\n");
236062306a36Sopenharmony_ci		return r;
236162306a36Sopenharmony_ci	}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_displays; ++i) {
236462306a36Sopenharmony_ci		struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci		if (dssdev == def_dssdev)
236762306a36Sopenharmony_ci			continue;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci		/*
237062306a36Sopenharmony_ci		 * We don't care if the connect succeeds or not. We just want to
237162306a36Sopenharmony_ci		 * connect as many displays as possible.
237262306a36Sopenharmony_ci		 */
237362306a36Sopenharmony_ci		dssdev->driver->connect(dssdev);
237462306a36Sopenharmony_ci	}
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	mgr = omapdss_find_mgr_from_display(def_dssdev);
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	if (!mgr) {
237962306a36Sopenharmony_ci		dev_err(fbdev->dev, "no ovl manager for the default display\n");
238062306a36Sopenharmony_ci		return -EINVAL;
238162306a36Sopenharmony_ci	}
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_overlays; i++) {
238462306a36Sopenharmony_ci		struct omap_overlay *ovl = fbdev->overlays[i];
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci		if (ovl->manager)
238762306a36Sopenharmony_ci			ovl->unset_manager(ovl);
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci		r = ovl->set_manager(ovl, mgr);
239062306a36Sopenharmony_ci		if (r)
239162306a36Sopenharmony_ci			dev_warn(fbdev->dev,
239262306a36Sopenharmony_ci					"failed to connect overlay %s to manager %s\n",
239362306a36Sopenharmony_ci					ovl->name, mgr->name);
239462306a36Sopenharmony_ci	}
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	return 0;
239762306a36Sopenharmony_ci}
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_cistatic struct omap_dss_device *
240062306a36Sopenharmony_ciomapfb_find_default_display(struct omapfb2_device *fbdev)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	const char *def_name;
240362306a36Sopenharmony_ci	int i;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	/*
240662306a36Sopenharmony_ci	 * Search with the display name from the user or the board file,
240762306a36Sopenharmony_ci	 * comparing to display names and aliases
240862306a36Sopenharmony_ci	 */
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	def_name = omapdss_get_default_display_name();
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	if (def_name) {
241362306a36Sopenharmony_ci		for (i = 0; i < fbdev->num_displays; ++i) {
241462306a36Sopenharmony_ci			struct omap_dss_device *dssdev;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci			dssdev = fbdev->displays[i].dssdev;
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci			if (dssdev->name && strcmp(def_name, dssdev->name) == 0)
241962306a36Sopenharmony_ci				return dssdev;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci			if (strcmp(def_name, dssdev->alias) == 0)
242262306a36Sopenharmony_ci				return dssdev;
242362306a36Sopenharmony_ci		}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci		/* def_name given but not found */
242662306a36Sopenharmony_ci		return NULL;
242762306a36Sopenharmony_ci	}
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	/* then look for DT alias display0 */
243062306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_displays; ++i) {
243162306a36Sopenharmony_ci		struct omap_dss_device *dssdev;
243262306a36Sopenharmony_ci		int id;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci		dssdev = fbdev->displays[i].dssdev;
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci		if (dssdev->dev->of_node == NULL)
243762306a36Sopenharmony_ci			continue;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci		id = of_alias_get_id(dssdev->dev->of_node, "display");
244062306a36Sopenharmony_ci		if (id == 0)
244162306a36Sopenharmony_ci			return dssdev;
244262306a36Sopenharmony_ci	}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	/* return the first display we have in the list */
244562306a36Sopenharmony_ci	return fbdev->displays[0].dssdev;
244662306a36Sopenharmony_ci}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_cistatic int omapfb_probe(struct platform_device *pdev)
244962306a36Sopenharmony_ci{
245062306a36Sopenharmony_ci	struct omapfb2_device *fbdev = NULL;
245162306a36Sopenharmony_ci	int r = 0;
245262306a36Sopenharmony_ci	int i;
245362306a36Sopenharmony_ci	struct omap_dss_device *def_display;
245462306a36Sopenharmony_ci	struct omap_dss_device *dssdev;
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	DBG("omapfb_probe\n");
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	if (omapdss_is_initialized() == false)
245962306a36Sopenharmony_ci		return -EPROBE_DEFER;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	if (pdev->num_resources != 0) {
246262306a36Sopenharmony_ci		dev_err(&pdev->dev, "probed for an unknown device\n");
246362306a36Sopenharmony_ci		r = -ENODEV;
246462306a36Sopenharmony_ci		goto err0;
246562306a36Sopenharmony_ci	}
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device),
246862306a36Sopenharmony_ci			GFP_KERNEL);
246962306a36Sopenharmony_ci	if (fbdev == NULL) {
247062306a36Sopenharmony_ci		r = -ENOMEM;
247162306a36Sopenharmony_ci		goto err0;
247262306a36Sopenharmony_ci	}
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	if (def_vrfb && !omap_vrfb_supported()) {
247562306a36Sopenharmony_ci		def_vrfb = 0;
247662306a36Sopenharmony_ci		dev_warn(&pdev->dev, "VRFB is not supported on this hardware, "
247762306a36Sopenharmony_ci				"ignoring the module parameter vrfb=y\n");
247862306a36Sopenharmony_ci	}
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	r = omapdss_compat_init();
248162306a36Sopenharmony_ci	if (r)
248262306a36Sopenharmony_ci		goto err0;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	mutex_init(&fbdev->mtx);
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	fbdev->dev = &pdev->dev;
248762306a36Sopenharmony_ci	platform_set_drvdata(pdev, fbdev);
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	fbdev->num_displays = 0;
249062306a36Sopenharmony_ci	dssdev = NULL;
249162306a36Sopenharmony_ci	for_each_dss_dev(dssdev) {
249262306a36Sopenharmony_ci		struct omapfb_display_data *d;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci		omap_dss_get_device(dssdev);
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci		if (!dssdev->driver) {
249762306a36Sopenharmony_ci			dev_warn(&pdev->dev, "no driver for display: %s\n",
249862306a36Sopenharmony_ci				dssdev->name);
249962306a36Sopenharmony_ci			omap_dss_put_device(dssdev);
250062306a36Sopenharmony_ci			continue;
250162306a36Sopenharmony_ci		}
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci		d = &fbdev->displays[fbdev->num_displays++];
250462306a36Sopenharmony_ci		d->dssdev = dssdev;
250562306a36Sopenharmony_ci		if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
250662306a36Sopenharmony_ci			d->update_mode = OMAPFB_MANUAL_UPDATE;
250762306a36Sopenharmony_ci		else
250862306a36Sopenharmony_ci			d->update_mode = OMAPFB_AUTO_UPDATE;
250962306a36Sopenharmony_ci	}
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	if (fbdev->num_displays == 0) {
251262306a36Sopenharmony_ci		dev_err(&pdev->dev, "no displays\n");
251362306a36Sopenharmony_ci		r = -EPROBE_DEFER;
251462306a36Sopenharmony_ci		goto cleanup;
251562306a36Sopenharmony_ci	}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	fbdev->num_overlays = omap_dss_get_num_overlays();
251862306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_overlays; i++)
251962306a36Sopenharmony_ci		fbdev->overlays[i] = omap_dss_get_overlay(i);
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci	fbdev->num_managers = omap_dss_get_num_overlay_managers();
252262306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_managers; i++)
252362306a36Sopenharmony_ci		fbdev->managers[i] = omap_dss_get_overlay_manager(i);
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	def_display = omapfb_find_default_display(fbdev);
252662306a36Sopenharmony_ci	if (def_display == NULL) {
252762306a36Sopenharmony_ci		dev_err(fbdev->dev, "failed to find default display\n");
252862306a36Sopenharmony_ci		r = -EPROBE_DEFER;
252962306a36Sopenharmony_ci		goto cleanup;
253062306a36Sopenharmony_ci	}
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	r = omapfb_init_connections(fbdev, def_display);
253362306a36Sopenharmony_ci	if (r) {
253462306a36Sopenharmony_ci		dev_err(fbdev->dev, "failed to init overlay connections\n");
253562306a36Sopenharmony_ci		goto cleanup;
253662306a36Sopenharmony_ci	}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	if (def_mode && strlen(def_mode) > 0) {
253962306a36Sopenharmony_ci		if (omapfb_parse_def_modes(fbdev))
254062306a36Sopenharmony_ci			dev_warn(&pdev->dev, "cannot parse default modes\n");
254162306a36Sopenharmony_ci	} else if (def_display && def_display->driver->set_timings &&
254262306a36Sopenharmony_ci			def_display->driver->check_timings) {
254362306a36Sopenharmony_ci		struct omap_video_timings t;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci		r = omapfb_find_best_mode(def_display, &t);
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci		if (r == 0)
254862306a36Sopenharmony_ci			def_display->driver->set_timings(def_display, &t);
254962306a36Sopenharmony_ci	}
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	r = omapfb_create_framebuffers(fbdev);
255262306a36Sopenharmony_ci	if (r)
255362306a36Sopenharmony_ci		goto cleanup;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_managers; i++) {
255662306a36Sopenharmony_ci		struct omap_overlay_manager *mgr;
255762306a36Sopenharmony_ci		mgr = fbdev->managers[i];
255862306a36Sopenharmony_ci		r = mgr->apply(mgr);
255962306a36Sopenharmony_ci		if (r)
256062306a36Sopenharmony_ci			dev_warn(fbdev->dev, "failed to apply dispc config\n");
256162306a36Sopenharmony_ci	}
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci	DBG("mgr->apply'ed\n");
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	if (def_display) {
256662306a36Sopenharmony_ci		r = omapfb_init_display(fbdev, def_display);
256762306a36Sopenharmony_ci		if (r) {
256862306a36Sopenharmony_ci			dev_err(fbdev->dev,
256962306a36Sopenharmony_ci					"failed to initialize default "
257062306a36Sopenharmony_ci					"display\n");
257162306a36Sopenharmony_ci			goto cleanup;
257262306a36Sopenharmony_ci		}
257362306a36Sopenharmony_ci	}
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	DBG("create sysfs for fbs\n");
257662306a36Sopenharmony_ci	r = omapfb_create_sysfs(fbdev);
257762306a36Sopenharmony_ci	if (r) {
257862306a36Sopenharmony_ci		dev_err(fbdev->dev, "failed to create sysfs entries\n");
257962306a36Sopenharmony_ci		goto cleanup;
258062306a36Sopenharmony_ci	}
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	if (def_display) {
258362306a36Sopenharmony_ci		u16 w, h;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci		def_display->driver->get_resolution(def_display, &w, &h);
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci		dev_info(fbdev->dev, "using display '%s' mode %dx%d\n",
258862306a36Sopenharmony_ci			def_display->name, w, h);
258962306a36Sopenharmony_ci	}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	return 0;
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_cicleanup:
259462306a36Sopenharmony_ci	omapfb_free_resources(fbdev);
259562306a36Sopenharmony_ci	omapdss_compat_uninit();
259662306a36Sopenharmony_cierr0:
259762306a36Sopenharmony_ci	dev_err(&pdev->dev, "failed to setup omapfb\n");
259862306a36Sopenharmony_ci	return r;
259962306a36Sopenharmony_ci}
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_cistatic void omapfb_remove(struct platform_device *pdev)
260262306a36Sopenharmony_ci{
260362306a36Sopenharmony_ci	struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	/* FIXME: wait till completion of pending events */
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	omapfb_remove_sysfs(fbdev);
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	omapfb_free_resources(fbdev);
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	omapdss_compat_uninit();
261262306a36Sopenharmony_ci}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_cistatic struct platform_driver omapfb_driver = {
261562306a36Sopenharmony_ci	.probe		= omapfb_probe,
261662306a36Sopenharmony_ci	.remove_new     = omapfb_remove,
261762306a36Sopenharmony_ci	.driver         = {
261862306a36Sopenharmony_ci		.name   = "omapfb",
261962306a36Sopenharmony_ci	},
262062306a36Sopenharmony_ci};
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_cimodule_param_named(mode, def_mode, charp, 0);
262362306a36Sopenharmony_cimodule_param_named(vram, def_vram, charp, 0);
262462306a36Sopenharmony_cimodule_param_named(rotate, def_rotate, int, 0);
262562306a36Sopenharmony_cimodule_param_named(vrfb, def_vrfb, bool, 0);
262662306a36Sopenharmony_cimodule_param_named(mirror, def_mirror, bool, 0);
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_cimodule_platform_driver(omapfb_driver);
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ciMODULE_ALIAS("platform:omapfb");
263162306a36Sopenharmony_ciMODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
263262306a36Sopenharmony_ciMODULE_DESCRIPTION("OMAP2/3 Framebuffer");
263362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2634