162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/drivers/video/omap2/omapfb-ioctl.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/fb.h>
1362306a36Sopenharmony_ci#include <linux/device.h>
1462306a36Sopenharmony_ci#include <linux/uaccess.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/mm.h>
1762306a36Sopenharmony_ci#include <linux/omapfb.h>
1862306a36Sopenharmony_ci#include <linux/vmalloc.h>
1962306a36Sopenharmony_ci#include <linux/export.h>
2062306a36Sopenharmony_ci#include <linux/sizes.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_cistatic u8 get_mem_idx(struct omapfb_info *ofbi)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	if (ofbi->id == ofbi->region->id)
3062306a36Sopenharmony_ci		return 0;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi,
3662306a36Sopenharmony_ci						 u8 mem_idx)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (mem_idx & OMAPFB_MEM_IDX_ENABLED)
4162306a36Sopenharmony_ci		mem_idx &= OMAPFB_MEM_IDX_MASK;
4262306a36Sopenharmony_ci	else
4362306a36Sopenharmony_ci		mem_idx = ofbi->id;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (mem_idx >= fbdev->num_fbs)
4662306a36Sopenharmony_ci		return NULL;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return &fbdev->regions[mem_idx];
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
5462306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
5562306a36Sopenharmony_ci	struct omap_overlay *ovl;
5662306a36Sopenharmony_ci	struct omap_overlay_info old_info;
5762306a36Sopenharmony_ci	struct omapfb2_mem_region *old_rg, *new_rg;
5862306a36Sopenharmony_ci	int r = 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	DBG("omapfb_setup_plane\n");
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (ofbi->num_overlays == 0) {
6362306a36Sopenharmony_ci		r = -EINVAL;
6462306a36Sopenharmony_ci		goto out;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* XXX uses only the first overlay */
6862306a36Sopenharmony_ci	ovl = ofbi->overlays[0];
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	old_rg = ofbi->region;
7162306a36Sopenharmony_ci	new_rg = get_mem_region(ofbi, pi->mem_idx);
7262306a36Sopenharmony_ci	if (!new_rg) {
7362306a36Sopenharmony_ci		r = -EINVAL;
7462306a36Sopenharmony_ci		goto out;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* Take the locks in a specific order to keep lockdep happy */
7862306a36Sopenharmony_ci	if (old_rg->id < new_rg->id) {
7962306a36Sopenharmony_ci		omapfb_get_mem_region(old_rg);
8062306a36Sopenharmony_ci		omapfb_get_mem_region(new_rg);
8162306a36Sopenharmony_ci	} else if (new_rg->id < old_rg->id) {
8262306a36Sopenharmony_ci		omapfb_get_mem_region(new_rg);
8362306a36Sopenharmony_ci		omapfb_get_mem_region(old_rg);
8462306a36Sopenharmony_ci	} else
8562306a36Sopenharmony_ci		omapfb_get_mem_region(old_rg);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (pi->enabled && !new_rg->size) {
8862306a36Sopenharmony_ci		/*
8962306a36Sopenharmony_ci		 * This plane's memory was freed, can't enable it
9062306a36Sopenharmony_ci		 * until it's reallocated.
9162306a36Sopenharmony_ci		 */
9262306a36Sopenharmony_ci		r = -EINVAL;
9362306a36Sopenharmony_ci		goto put_mem;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	ovl->get_overlay_info(ovl, &old_info);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (old_rg != new_rg) {
9962306a36Sopenharmony_ci		ofbi->region = new_rg;
10062306a36Sopenharmony_ci		set_fb_fix(fbi);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (!pi->enabled) {
10462306a36Sopenharmony_ci		r = ovl->disable(ovl);
10562306a36Sopenharmony_ci		if (r)
10662306a36Sopenharmony_ci			goto undo;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (pi->enabled) {
11062306a36Sopenharmony_ci		r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
11162306a36Sopenharmony_ci			pi->out_width, pi->out_height);
11262306a36Sopenharmony_ci		if (r)
11362306a36Sopenharmony_ci			goto undo;
11462306a36Sopenharmony_ci	} else {
11562306a36Sopenharmony_ci		struct omap_overlay_info info;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		ovl->get_overlay_info(ovl, &info);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		info.pos_x = pi->pos_x;
12062306a36Sopenharmony_ci		info.pos_y = pi->pos_y;
12162306a36Sopenharmony_ci		info.out_width = pi->out_width;
12262306a36Sopenharmony_ci		info.out_height = pi->out_height;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		r = ovl->set_overlay_info(ovl, &info);
12562306a36Sopenharmony_ci		if (r)
12662306a36Sopenharmony_ci			goto undo;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (ovl->manager) {
13062306a36Sopenharmony_ci		r = ovl->manager->apply(ovl->manager);
13162306a36Sopenharmony_ci		if (r)
13262306a36Sopenharmony_ci			goto undo;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (pi->enabled) {
13662306a36Sopenharmony_ci		r = ovl->enable(ovl);
13762306a36Sopenharmony_ci		if (r)
13862306a36Sopenharmony_ci			goto undo;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Release the locks in a specific order to keep lockdep happy */
14262306a36Sopenharmony_ci	if (old_rg->id > new_rg->id) {
14362306a36Sopenharmony_ci		omapfb_put_mem_region(old_rg);
14462306a36Sopenharmony_ci		omapfb_put_mem_region(new_rg);
14562306a36Sopenharmony_ci	} else if (new_rg->id > old_rg->id) {
14662306a36Sopenharmony_ci		omapfb_put_mem_region(new_rg);
14762306a36Sopenharmony_ci		omapfb_put_mem_region(old_rg);
14862306a36Sopenharmony_ci	} else
14962306a36Sopenharmony_ci		omapfb_put_mem_region(old_rg);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return 0;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci undo:
15462306a36Sopenharmony_ci	if (old_rg != new_rg) {
15562306a36Sopenharmony_ci		ofbi->region = old_rg;
15662306a36Sopenharmony_ci		set_fb_fix(fbi);
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	ovl->set_overlay_info(ovl, &old_info);
16062306a36Sopenharmony_ci put_mem:
16162306a36Sopenharmony_ci	/* Release the locks in a specific order to keep lockdep happy */
16262306a36Sopenharmony_ci	if (old_rg->id > new_rg->id) {
16362306a36Sopenharmony_ci		omapfb_put_mem_region(old_rg);
16462306a36Sopenharmony_ci		omapfb_put_mem_region(new_rg);
16562306a36Sopenharmony_ci	} else if (new_rg->id > old_rg->id) {
16662306a36Sopenharmony_ci		omapfb_put_mem_region(new_rg);
16762306a36Sopenharmony_ci		omapfb_put_mem_region(old_rg);
16862306a36Sopenharmony_ci	} else
16962306a36Sopenharmony_ci		omapfb_put_mem_region(old_rg);
17062306a36Sopenharmony_ci out:
17162306a36Sopenharmony_ci	dev_err(fbdev->dev, "setup_plane failed\n");
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return r;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (ofbi->num_overlays == 0) {
18162306a36Sopenharmony_ci		memset(pi, 0, sizeof(*pi));
18262306a36Sopenharmony_ci	} else {
18362306a36Sopenharmony_ci		struct omap_overlay *ovl;
18462306a36Sopenharmony_ci		struct omap_overlay_info ovli;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		ovl = ofbi->overlays[0];
18762306a36Sopenharmony_ci		ovl->get_overlay_info(ovl, &ovli);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		pi->pos_x = ovli.pos_x;
19062306a36Sopenharmony_ci		pi->pos_y = ovli.pos_y;
19162306a36Sopenharmony_ci		pi->enabled = ovl->is_enabled(ovl);
19262306a36Sopenharmony_ci		pi->channel_out = 0; /* xxx */
19362306a36Sopenharmony_ci		pi->mirror = 0;
19462306a36Sopenharmony_ci		pi->mem_idx = get_mem_idx(ofbi);
19562306a36Sopenharmony_ci		pi->out_width = ovli.out_width;
19662306a36Sopenharmony_ci		pi->out_height = ovli.out_height;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return 0;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
20562306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
20662306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
20762306a36Sopenharmony_ci	struct omapfb2_mem_region *rg;
20862306a36Sopenharmony_ci	int r = 0, i;
20962306a36Sopenharmony_ci	size_t size;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (mi->type != OMAPFB_MEMTYPE_SDRAM)
21262306a36Sopenharmony_ci		return -EINVAL;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	size = PAGE_ALIGN(mi->size);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (display && display->driver->sync)
21762306a36Sopenharmony_ci		display->driver->sync(display);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	rg = ofbi->region;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	down_write_nested(&rg->lock, rg->id);
22262306a36Sopenharmony_ci	atomic_inc(&rg->lock_count);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (rg->size == size && rg->type == mi->type)
22562306a36Sopenharmony_ci		goto out;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (atomic_read(&rg->map_count)) {
22862306a36Sopenharmony_ci		r = -EBUSY;
22962306a36Sopenharmony_ci		goto out;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
23362306a36Sopenharmony_ci		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
23462306a36Sopenharmony_ci		int j;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci		if (ofbi2->region != rg)
23762306a36Sopenharmony_ci			continue;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		for (j = 0; j < ofbi2->num_overlays; j++) {
24062306a36Sopenharmony_ci			struct omap_overlay *ovl;
24162306a36Sopenharmony_ci			ovl = ofbi2->overlays[j];
24262306a36Sopenharmony_ci			if (ovl->is_enabled(ovl)) {
24362306a36Sopenharmony_ci				r = -EBUSY;
24462306a36Sopenharmony_ci				goto out;
24562306a36Sopenharmony_ci			}
24662306a36Sopenharmony_ci		}
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	r = omapfb_realloc_fbmem(fbi, size, mi->type);
25062306a36Sopenharmony_ci	if (r) {
25162306a36Sopenharmony_ci		dev_err(fbdev->dev, "realloc fbmem failed\n");
25262306a36Sopenharmony_ci		goto out;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci out:
25662306a36Sopenharmony_ci	atomic_dec(&rg->lock_count);
25762306a36Sopenharmony_ci	up_write(&rg->lock);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return r;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
26562306a36Sopenharmony_ci	struct omapfb2_mem_region *rg;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	rg = omapfb_get_mem_region(ofbi->region);
26862306a36Sopenharmony_ci	memset(mi, 0, sizeof(*mi));
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	mi->size = rg->size;
27162306a36Sopenharmony_ci	mi->type = rg->type;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	omapfb_put_mem_region(rg);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic int omapfb_update_window(struct fb_info *fbi,
27962306a36Sopenharmony_ci		u32 x, u32 y, u32 w, u32 h)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
28262306a36Sopenharmony_ci	u16 dw, dh;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (!display)
28562306a36Sopenharmony_ci		return 0;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (w == 0 || h == 0)
28862306a36Sopenharmony_ci		return 0;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	display->driver->get_resolution(display, &dw, &dh);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (x + w > dw || y + h > dh)
29362306a36Sopenharmony_ci		return -EINVAL;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return display->driver->update(display, x, y, w, h);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ciint omapfb_set_update_mode(struct fb_info *fbi,
29962306a36Sopenharmony_ci				   enum omapfb_update_mode mode)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
30262306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
30362306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
30462306a36Sopenharmony_ci	struct omapfb_display_data *d;
30562306a36Sopenharmony_ci	int r;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (!display)
30862306a36Sopenharmony_ci		return -EINVAL;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
31162306a36Sopenharmony_ci		return -EINVAL;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	omapfb_lock(fbdev);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	d = get_display_data(fbdev, display);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (d->update_mode == mode) {
31862306a36Sopenharmony_ci		omapfb_unlock(fbdev);
31962306a36Sopenharmony_ci		return 0;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	r = 0;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
32562306a36Sopenharmony_ci		if (mode == OMAPFB_AUTO_UPDATE)
32662306a36Sopenharmony_ci			omapfb_start_auto_update(fbdev, display);
32762306a36Sopenharmony_ci		else /* MANUAL_UPDATE */
32862306a36Sopenharmony_ci			omapfb_stop_auto_update(fbdev, display);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		d->update_mode = mode;
33162306a36Sopenharmony_ci	} else { /* AUTO_UPDATE */
33262306a36Sopenharmony_ci		if (mode == OMAPFB_MANUAL_UPDATE)
33362306a36Sopenharmony_ci			r = -EINVAL;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	omapfb_unlock(fbdev);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	return r;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ciint omapfb_get_update_mode(struct fb_info *fbi,
34262306a36Sopenharmony_ci		enum omapfb_update_mode *mode)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
34562306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
34662306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
34762306a36Sopenharmony_ci	struct omapfb_display_data *d;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (!display)
35062306a36Sopenharmony_ci		return -EINVAL;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	omapfb_lock(fbdev);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	d = get_display_data(fbdev, display);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	*mode = d->update_mode;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	omapfb_unlock(fbdev);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return 0;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/* XXX this color key handling is a hack... */
36462306a36Sopenharmony_cistatic struct omapfb_color_key omapfb_color_keys[2];
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
36762306a36Sopenharmony_ci		struct omapfb_color_key *ck)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct omap_overlay_manager_info info;
37062306a36Sopenharmony_ci	enum omap_dss_trans_key_type kt;
37162306a36Sopenharmony_ci	int r;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	mgr->get_manager_info(mgr, &info);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
37662306a36Sopenharmony_ci		info.trans_enabled = false;
37762306a36Sopenharmony_ci		omapfb_color_keys[mgr->id] = *ck;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		r = mgr->set_manager_info(mgr, &info);
38062306a36Sopenharmony_ci		if (r)
38162306a36Sopenharmony_ci			return r;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		r = mgr->apply(mgr);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		return r;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	switch (ck->key_type) {
38962306a36Sopenharmony_ci	case OMAPFB_COLOR_KEY_GFX_DST:
39062306a36Sopenharmony_ci		kt = OMAP_DSS_COLOR_KEY_GFX_DST;
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	case OMAPFB_COLOR_KEY_VID_SRC:
39362306a36Sopenharmony_ci		kt = OMAP_DSS_COLOR_KEY_VID_SRC;
39462306a36Sopenharmony_ci		break;
39562306a36Sopenharmony_ci	default:
39662306a36Sopenharmony_ci		return -EINVAL;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	info.default_color = ck->background;
40062306a36Sopenharmony_ci	info.trans_key = ck->trans_key;
40162306a36Sopenharmony_ci	info.trans_key_type = kt;
40262306a36Sopenharmony_ci	info.trans_enabled = true;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	omapfb_color_keys[mgr->id] = *ck;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	r = mgr->set_manager_info(mgr, &info);
40762306a36Sopenharmony_ci	if (r)
40862306a36Sopenharmony_ci		return r;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	r = mgr->apply(mgr);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return r;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic int omapfb_set_color_key(struct fb_info *fbi,
41662306a36Sopenharmony_ci		struct omapfb_color_key *ck)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
41962306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
42062306a36Sopenharmony_ci	int r;
42162306a36Sopenharmony_ci	int i;
42262306a36Sopenharmony_ci	struct omap_overlay_manager *mgr = NULL;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	omapfb_lock(fbdev);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	for (i = 0; i < ofbi->num_overlays; i++) {
42762306a36Sopenharmony_ci		if (ofbi->overlays[i]->manager) {
42862306a36Sopenharmony_ci			mgr = ofbi->overlays[i]->manager;
42962306a36Sopenharmony_ci			break;
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if (!mgr) {
43462306a36Sopenharmony_ci		r = -EINVAL;
43562306a36Sopenharmony_ci		goto err;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	r = _omapfb_set_color_key(mgr, ck);
43962306a36Sopenharmony_cierr:
44062306a36Sopenharmony_ci	omapfb_unlock(fbdev);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return r;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic int omapfb_get_color_key(struct fb_info *fbi,
44662306a36Sopenharmony_ci		struct omapfb_color_key *ck)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
44962306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
45062306a36Sopenharmony_ci	struct omap_overlay_manager *mgr = NULL;
45162306a36Sopenharmony_ci	int r = 0;
45262306a36Sopenharmony_ci	int i;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	omapfb_lock(fbdev);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	for (i = 0; i < ofbi->num_overlays; i++) {
45762306a36Sopenharmony_ci		if (ofbi->overlays[i]->manager) {
45862306a36Sopenharmony_ci			mgr = ofbi->overlays[i]->manager;
45962306a36Sopenharmony_ci			break;
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (!mgr) {
46462306a36Sopenharmony_ci		r = -EINVAL;
46562306a36Sopenharmony_ci		goto err;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	*ck = omapfb_color_keys[mgr->id];
46962306a36Sopenharmony_cierr:
47062306a36Sopenharmony_ci	omapfb_unlock(fbdev);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return r;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int omapfb_memory_read(struct fb_info *fbi,
47662306a36Sopenharmony_ci		struct omapfb_memory_read *mr)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
47962306a36Sopenharmony_ci	void *buf;
48062306a36Sopenharmony_ci	int r;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (!display || !display->driver->memory_read)
48362306a36Sopenharmony_ci		return -ENOENT;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (mr->w > 4096 || mr->h > 4096)
48662306a36Sopenharmony_ci		return -EINVAL;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (mr->w * mr->h * 3 > mr->buffer_size)
48962306a36Sopenharmony_ci		return -EINVAL;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	buf = vmalloc(mr->buffer_size);
49262306a36Sopenharmony_ci	if (!buf) {
49362306a36Sopenharmony_ci		DBG("vmalloc failed\n");
49462306a36Sopenharmony_ci		return -ENOMEM;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	r = display->driver->memory_read(display, buf, mr->buffer_size,
49862306a36Sopenharmony_ci			mr->x, mr->y, mr->w, mr->h);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (r > 0) {
50162306a36Sopenharmony_ci		if (copy_to_user(mr->buffer, buf, r))
50262306a36Sopenharmony_ci			r = -EFAULT;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	vfree(buf);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	return r;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
51162306a36Sopenharmony_ci			     struct omapfb_ovl_colormode *mode)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	int ovl_idx = mode->overlay_idx;
51462306a36Sopenharmony_ci	int mode_idx = mode->mode_idx;
51562306a36Sopenharmony_ci	struct omap_overlay *ovl;
51662306a36Sopenharmony_ci	enum omap_color_mode supported_modes;
51762306a36Sopenharmony_ci	struct fb_var_screeninfo var;
51862306a36Sopenharmony_ci	int i;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (ovl_idx >= fbdev->num_overlays)
52162306a36Sopenharmony_ci		return -ENODEV;
52262306a36Sopenharmony_ci	ovl = fbdev->overlays[ovl_idx];
52362306a36Sopenharmony_ci	supported_modes = ovl->supported_modes;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	mode_idx = mode->mode_idx;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	for (i = 0; i < sizeof(supported_modes) * 8; i++) {
52862306a36Sopenharmony_ci		if (!(supported_modes & (1 << i)))
52962306a36Sopenharmony_ci			continue;
53062306a36Sopenharmony_ci		/*
53162306a36Sopenharmony_ci		 * It's possible that the FB doesn't support a mode
53262306a36Sopenharmony_ci		 * that is supported by the overlay, so call the
53362306a36Sopenharmony_ci		 * following here.
53462306a36Sopenharmony_ci		 */
53562306a36Sopenharmony_ci		if (dss_mode_to_fb_mode(1 << i, &var) < 0)
53662306a36Sopenharmony_ci			continue;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci		mode_idx--;
53962306a36Sopenharmony_ci		if (mode_idx < 0)
54062306a36Sopenharmony_ci			break;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (i == sizeof(supported_modes) * 8)
54462306a36Sopenharmony_ci		return -ENOENT;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	mode->bits_per_pixel = var.bits_per_pixel;
54762306a36Sopenharmony_ci	mode->nonstd = var.nonstd;
54862306a36Sopenharmony_ci	mode->red = var.red;
54962306a36Sopenharmony_ci	mode->green = var.green;
55062306a36Sopenharmony_ci	mode->blue = var.blue;
55162306a36Sopenharmony_ci	mode->transp = var.transp;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic int omapfb_wait_for_go(struct fb_info *fbi)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
55962306a36Sopenharmony_ci	int r = 0;
56062306a36Sopenharmony_ci	int i;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	for (i = 0; i < ofbi->num_overlays; ++i) {
56362306a36Sopenharmony_ci		struct omap_overlay *ovl = ofbi->overlays[i];
56462306a36Sopenharmony_ci		r = ovl->wait_for_go(ovl);
56562306a36Sopenharmony_ci		if (r)
56662306a36Sopenharmony_ci			break;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	return r;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ciint omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
57562306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
57662306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
57762306a36Sopenharmony_ci	struct omap_overlay_manager *mgr;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	union {
58062306a36Sopenharmony_ci		struct omapfb_update_window_old	uwnd_o;
58162306a36Sopenharmony_ci		struct omapfb_update_window	uwnd;
58262306a36Sopenharmony_ci		struct omapfb_plane_info	plane_info;
58362306a36Sopenharmony_ci		struct omapfb_caps		caps;
58462306a36Sopenharmony_ci		struct omapfb_mem_info          mem_info;
58562306a36Sopenharmony_ci		struct omapfb_color_key		color_key;
58662306a36Sopenharmony_ci		struct omapfb_ovl_colormode	ovl_colormode;
58762306a36Sopenharmony_ci		enum omapfb_update_mode		update_mode;
58862306a36Sopenharmony_ci		int test_num;
58962306a36Sopenharmony_ci		struct omapfb_memory_read	memory_read;
59062306a36Sopenharmony_ci		struct omapfb_vram_info		vram_info;
59162306a36Sopenharmony_ci		struct omapfb_tearsync_info	tearsync_info;
59262306a36Sopenharmony_ci		struct omapfb_display_info	display_info;
59362306a36Sopenharmony_ci		u32				crt;
59462306a36Sopenharmony_ci	} p;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	int r = 0;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	memset(&p, 0, sizeof(p));
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	switch (cmd) {
60162306a36Sopenharmony_ci	case OMAPFB_SYNC_GFX:
60262306a36Sopenharmony_ci		DBG("ioctl SYNC_GFX\n");
60362306a36Sopenharmony_ci		if (!display || !display->driver->sync) {
60462306a36Sopenharmony_ci			/* DSS1 never returns an error here, so we neither */
60562306a36Sopenharmony_ci			/*r = -EINVAL;*/
60662306a36Sopenharmony_ci			break;
60762306a36Sopenharmony_ci		}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		r = display->driver->sync(display);
61062306a36Sopenharmony_ci		break;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	case OMAPFB_UPDATE_WINDOW_OLD:
61362306a36Sopenharmony_ci		DBG("ioctl UPDATE_WINDOW_OLD\n");
61462306a36Sopenharmony_ci		if (!display || !display->driver->update) {
61562306a36Sopenharmony_ci			r = -EINVAL;
61662306a36Sopenharmony_ci			break;
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		if (copy_from_user(&p.uwnd_o,
62062306a36Sopenharmony_ci					(void __user *)arg,
62162306a36Sopenharmony_ci					sizeof(p.uwnd_o))) {
62262306a36Sopenharmony_ci			r = -EFAULT;
62362306a36Sopenharmony_ci			break;
62462306a36Sopenharmony_ci		}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
62762306a36Sopenharmony_ci				p.uwnd_o.width, p.uwnd_o.height);
62862306a36Sopenharmony_ci		break;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	case OMAPFB_UPDATE_WINDOW:
63162306a36Sopenharmony_ci		DBG("ioctl UPDATE_WINDOW\n");
63262306a36Sopenharmony_ci		if (!display || !display->driver->update) {
63362306a36Sopenharmony_ci			r = -EINVAL;
63462306a36Sopenharmony_ci			break;
63562306a36Sopenharmony_ci		}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		if (copy_from_user(&p.uwnd, (void __user *)arg,
63862306a36Sopenharmony_ci					sizeof(p.uwnd))) {
63962306a36Sopenharmony_ci			r = -EFAULT;
64062306a36Sopenharmony_ci			break;
64162306a36Sopenharmony_ci		}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
64462306a36Sopenharmony_ci				p.uwnd.width, p.uwnd.height);
64562306a36Sopenharmony_ci		break;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	case OMAPFB_SETUP_PLANE:
64862306a36Sopenharmony_ci		DBG("ioctl SETUP_PLANE\n");
64962306a36Sopenharmony_ci		if (copy_from_user(&p.plane_info, (void __user *)arg,
65062306a36Sopenharmony_ci					sizeof(p.plane_info)))
65162306a36Sopenharmony_ci			r = -EFAULT;
65262306a36Sopenharmony_ci		else
65362306a36Sopenharmony_ci			r = omapfb_setup_plane(fbi, &p.plane_info);
65462306a36Sopenharmony_ci		break;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	case OMAPFB_QUERY_PLANE:
65762306a36Sopenharmony_ci		DBG("ioctl QUERY_PLANE\n");
65862306a36Sopenharmony_ci		r = omapfb_query_plane(fbi, &p.plane_info);
65962306a36Sopenharmony_ci		if (r < 0)
66062306a36Sopenharmony_ci			break;
66162306a36Sopenharmony_ci		if (copy_to_user((void __user *)arg, &p.plane_info,
66262306a36Sopenharmony_ci					sizeof(p.plane_info)))
66362306a36Sopenharmony_ci			r = -EFAULT;
66462306a36Sopenharmony_ci		break;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	case OMAPFB_SETUP_MEM:
66762306a36Sopenharmony_ci		DBG("ioctl SETUP_MEM\n");
66862306a36Sopenharmony_ci		if (copy_from_user(&p.mem_info, (void __user *)arg,
66962306a36Sopenharmony_ci					sizeof(p.mem_info)))
67062306a36Sopenharmony_ci			r = -EFAULT;
67162306a36Sopenharmony_ci		else
67262306a36Sopenharmony_ci			r = omapfb_setup_mem(fbi, &p.mem_info);
67362306a36Sopenharmony_ci		break;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	case OMAPFB_QUERY_MEM:
67662306a36Sopenharmony_ci		DBG("ioctl QUERY_MEM\n");
67762306a36Sopenharmony_ci		r = omapfb_query_mem(fbi, &p.mem_info);
67862306a36Sopenharmony_ci		if (r < 0)
67962306a36Sopenharmony_ci			break;
68062306a36Sopenharmony_ci		if (copy_to_user((void __user *)arg, &p.mem_info,
68162306a36Sopenharmony_ci					sizeof(p.mem_info)))
68262306a36Sopenharmony_ci			r = -EFAULT;
68362306a36Sopenharmony_ci		break;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	case OMAPFB_GET_CAPS:
68662306a36Sopenharmony_ci		DBG("ioctl GET_CAPS\n");
68762306a36Sopenharmony_ci		if (!display) {
68862306a36Sopenharmony_ci			r = -EINVAL;
68962306a36Sopenharmony_ci			break;
69062306a36Sopenharmony_ci		}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		memset(&p.caps, 0, sizeof(p.caps));
69362306a36Sopenharmony_ci		if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
69462306a36Sopenharmony_ci			p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
69562306a36Sopenharmony_ci		if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
69662306a36Sopenharmony_ci			p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci		if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
69962306a36Sopenharmony_ci			r = -EFAULT;
70062306a36Sopenharmony_ci		break;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	case OMAPFB_GET_OVERLAY_COLORMODE:
70362306a36Sopenharmony_ci		DBG("ioctl GET_OVERLAY_COLORMODE\n");
70462306a36Sopenharmony_ci		if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
70562306a36Sopenharmony_ci				   sizeof(p.ovl_colormode))) {
70662306a36Sopenharmony_ci			r = -EFAULT;
70762306a36Sopenharmony_ci			break;
70862306a36Sopenharmony_ci		}
70962306a36Sopenharmony_ci		r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
71062306a36Sopenharmony_ci		if (r < 0)
71162306a36Sopenharmony_ci			break;
71262306a36Sopenharmony_ci		if (copy_to_user((void __user *)arg, &p.ovl_colormode,
71362306a36Sopenharmony_ci				 sizeof(p.ovl_colormode)))
71462306a36Sopenharmony_ci			r = -EFAULT;
71562306a36Sopenharmony_ci		break;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	case OMAPFB_SET_UPDATE_MODE:
71862306a36Sopenharmony_ci		DBG("ioctl SET_UPDATE_MODE\n");
71962306a36Sopenharmony_ci		if (get_user(p.update_mode, (int __user *)arg))
72062306a36Sopenharmony_ci			r = -EFAULT;
72162306a36Sopenharmony_ci		else
72262306a36Sopenharmony_ci			r = omapfb_set_update_mode(fbi, p.update_mode);
72362306a36Sopenharmony_ci		break;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	case OMAPFB_GET_UPDATE_MODE:
72662306a36Sopenharmony_ci		DBG("ioctl GET_UPDATE_MODE\n");
72762306a36Sopenharmony_ci		r = omapfb_get_update_mode(fbi, &p.update_mode);
72862306a36Sopenharmony_ci		if (r)
72962306a36Sopenharmony_ci			break;
73062306a36Sopenharmony_ci		if (put_user(p.update_mode,
73162306a36Sopenharmony_ci					(enum omapfb_update_mode __user *)arg))
73262306a36Sopenharmony_ci			r = -EFAULT;
73362306a36Sopenharmony_ci		break;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	case OMAPFB_SET_COLOR_KEY:
73662306a36Sopenharmony_ci		DBG("ioctl SET_COLOR_KEY\n");
73762306a36Sopenharmony_ci		if (copy_from_user(&p.color_key, (void __user *)arg,
73862306a36Sopenharmony_ci				   sizeof(p.color_key)))
73962306a36Sopenharmony_ci			r = -EFAULT;
74062306a36Sopenharmony_ci		else
74162306a36Sopenharmony_ci			r = omapfb_set_color_key(fbi, &p.color_key);
74262306a36Sopenharmony_ci		break;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	case OMAPFB_GET_COLOR_KEY:
74562306a36Sopenharmony_ci		DBG("ioctl GET_COLOR_KEY\n");
74662306a36Sopenharmony_ci		r = omapfb_get_color_key(fbi, &p.color_key);
74762306a36Sopenharmony_ci		if (r)
74862306a36Sopenharmony_ci			break;
74962306a36Sopenharmony_ci		if (copy_to_user((void __user *)arg, &p.color_key,
75062306a36Sopenharmony_ci				 sizeof(p.color_key)))
75162306a36Sopenharmony_ci			r = -EFAULT;
75262306a36Sopenharmony_ci		break;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	case FBIO_WAITFORVSYNC:
75562306a36Sopenharmony_ci		if (get_user(p.crt, (__u32 __user *)arg)) {
75662306a36Sopenharmony_ci			r = -EFAULT;
75762306a36Sopenharmony_ci			break;
75862306a36Sopenharmony_ci		}
75962306a36Sopenharmony_ci		if (p.crt != 0) {
76062306a36Sopenharmony_ci			r = -ENODEV;
76162306a36Sopenharmony_ci			break;
76262306a36Sopenharmony_ci		}
76362306a36Sopenharmony_ci		fallthrough;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	case OMAPFB_WAITFORVSYNC:
76662306a36Sopenharmony_ci		DBG("ioctl WAITFORVSYNC\n");
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		if (!display) {
76962306a36Sopenharmony_ci			r = -EINVAL;
77062306a36Sopenharmony_ci			break;
77162306a36Sopenharmony_ci		}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		mgr = omapdss_find_mgr_from_display(display);
77462306a36Sopenharmony_ci		if (!mgr) {
77562306a36Sopenharmony_ci			r = -EINVAL;
77662306a36Sopenharmony_ci			break;
77762306a36Sopenharmony_ci		}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		r = mgr->wait_for_vsync(mgr);
78062306a36Sopenharmony_ci		break;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	case OMAPFB_WAITFORGO:
78362306a36Sopenharmony_ci		DBG("ioctl WAITFORGO\n");
78462306a36Sopenharmony_ci		if (!display) {
78562306a36Sopenharmony_ci			r = -EINVAL;
78662306a36Sopenharmony_ci			break;
78762306a36Sopenharmony_ci		}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		r = omapfb_wait_for_go(fbi);
79062306a36Sopenharmony_ci		break;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/* LCD and CTRL tests do the same thing for backward
79362306a36Sopenharmony_ci	 * compatibility */
79462306a36Sopenharmony_ci	case OMAPFB_LCD_TEST:
79562306a36Sopenharmony_ci		DBG("ioctl LCD_TEST\n");
79662306a36Sopenharmony_ci		if (get_user(p.test_num, (int __user *)arg)) {
79762306a36Sopenharmony_ci			r = -EFAULT;
79862306a36Sopenharmony_ci			break;
79962306a36Sopenharmony_ci		}
80062306a36Sopenharmony_ci		if (!display || !display->driver->run_test) {
80162306a36Sopenharmony_ci			r = -EINVAL;
80262306a36Sopenharmony_ci			break;
80362306a36Sopenharmony_ci		}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		r = display->driver->run_test(display, p.test_num);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		break;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	case OMAPFB_CTRL_TEST:
81062306a36Sopenharmony_ci		DBG("ioctl CTRL_TEST\n");
81162306a36Sopenharmony_ci		if (get_user(p.test_num, (int __user *)arg)) {
81262306a36Sopenharmony_ci			r = -EFAULT;
81362306a36Sopenharmony_ci			break;
81462306a36Sopenharmony_ci		}
81562306a36Sopenharmony_ci		if (!display || !display->driver->run_test) {
81662306a36Sopenharmony_ci			r = -EINVAL;
81762306a36Sopenharmony_ci			break;
81862306a36Sopenharmony_ci		}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci		r = display->driver->run_test(display, p.test_num);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	case OMAPFB_MEMORY_READ:
82562306a36Sopenharmony_ci		DBG("ioctl MEMORY_READ\n");
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci		if (copy_from_user(&p.memory_read, (void __user *)arg,
82862306a36Sopenharmony_ci					sizeof(p.memory_read))) {
82962306a36Sopenharmony_ci			r = -EFAULT;
83062306a36Sopenharmony_ci			break;
83162306a36Sopenharmony_ci		}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		r = omapfb_memory_read(fbi, &p.memory_read);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		break;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	case OMAPFB_GET_VRAM_INFO: {
83862306a36Sopenharmony_ci		DBG("ioctl GET_VRAM_INFO\n");
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		/*
84162306a36Sopenharmony_ci		 * We don't have the ability to get this vram info anymore.
84262306a36Sopenharmony_ci		 * Fill in something that should keep the applications working.
84362306a36Sopenharmony_ci		 */
84462306a36Sopenharmony_ci		p.vram_info.total = SZ_1M * 64;
84562306a36Sopenharmony_ci		p.vram_info.free = SZ_1M * 64;
84662306a36Sopenharmony_ci		p.vram_info.largest_free_block = SZ_1M * 64;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci		if (copy_to_user((void __user *)arg, &p.vram_info,
84962306a36Sopenharmony_ci					sizeof(p.vram_info)))
85062306a36Sopenharmony_ci			r = -EFAULT;
85162306a36Sopenharmony_ci		break;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	case OMAPFB_SET_TEARSYNC: {
85562306a36Sopenharmony_ci		DBG("ioctl SET_TEARSYNC\n");
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci		if (copy_from_user(&p.tearsync_info, (void __user *)arg,
85862306a36Sopenharmony_ci					sizeof(p.tearsync_info))) {
85962306a36Sopenharmony_ci			r = -EFAULT;
86062306a36Sopenharmony_ci			break;
86162306a36Sopenharmony_ci		}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		if (!display || !display->driver->enable_te) {
86462306a36Sopenharmony_ci			r = -ENODEV;
86562306a36Sopenharmony_ci			break;
86662306a36Sopenharmony_ci		}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci		r = display->driver->enable_te(display,
86962306a36Sopenharmony_ci				!!p.tearsync_info.enabled);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		break;
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	case OMAPFB_GET_DISPLAY_INFO: {
87562306a36Sopenharmony_ci		u16 xres, yres;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci		DBG("ioctl GET_DISPLAY_INFO\n");
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci		if (display == NULL) {
88062306a36Sopenharmony_ci			r = -ENODEV;
88162306a36Sopenharmony_ci			break;
88262306a36Sopenharmony_ci		}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci		display->driver->get_resolution(display, &xres, &yres);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		p.display_info.xres = xres;
88762306a36Sopenharmony_ci		p.display_info.yres = yres;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci		if (display->driver->get_dimensions) {
89062306a36Sopenharmony_ci			u32 w, h;
89162306a36Sopenharmony_ci			display->driver->get_dimensions(display, &w, &h);
89262306a36Sopenharmony_ci			p.display_info.width = w;
89362306a36Sopenharmony_ci			p.display_info.height = h;
89462306a36Sopenharmony_ci		} else {
89562306a36Sopenharmony_ci			p.display_info.width = 0;
89662306a36Sopenharmony_ci			p.display_info.height = 0;
89762306a36Sopenharmony_ci		}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci		if (copy_to_user((void __user *)arg, &p.display_info,
90062306a36Sopenharmony_ci					sizeof(p.display_info)))
90162306a36Sopenharmony_ci			r = -EFAULT;
90262306a36Sopenharmony_ci		break;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	default:
90662306a36Sopenharmony_ci		dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
90762306a36Sopenharmony_ci		r = -EINVAL;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (r < 0)
91162306a36Sopenharmony_ci		DBG("ioctl failed: %d\n", r);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	return r;
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci
917