brintos

brintos / linux-shallow public Read only

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