162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/drivers/video/omap2/omapfb-sysfs.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/sysfs.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/uaccess.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/kstrtox.h>
1962306a36Sopenharmony_ci#include <linux/mm.h>
2062306a36Sopenharmony_ci#include <linux/omapfb.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <video/omapfb_dss.h>
2362306a36Sopenharmony_ci#include <video/omapvrfb.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "omapfb.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic ssize_t show_rotate_type(struct device *dev,
2862306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
3162306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", ofbi->rotation_type);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic ssize_t store_rotate_type(struct device *dev,
3762306a36Sopenharmony_ci		struct device_attribute *attr,
3862306a36Sopenharmony_ci		const char *buf, size_t count)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
4162306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
4262306a36Sopenharmony_ci	struct omapfb2_mem_region *rg;
4362306a36Sopenharmony_ci	int rot_type;
4462306a36Sopenharmony_ci	int r;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	r = kstrtoint(buf, 0, &rot_type);
4762306a36Sopenharmony_ci	if (r)
4862306a36Sopenharmony_ci		return r;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
5162306a36Sopenharmony_ci		return -EINVAL;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	lock_fb_info(fbi);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	r = 0;
5662306a36Sopenharmony_ci	if (rot_type == ofbi->rotation_type)
5762306a36Sopenharmony_ci		goto out;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	rg = omapfb_get_mem_region(ofbi->region);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (rg->size) {
6262306a36Sopenharmony_ci		r = -EBUSY;
6362306a36Sopenharmony_ci		goto put_region;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	ofbi->rotation_type = rot_type;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/*
6962306a36Sopenharmony_ci	 * Since the VRAM for this FB is not allocated at the moment we don't
7062306a36Sopenharmony_ci	 * need to do any further parameter checking at this point.
7162306a36Sopenharmony_ci	 */
7262306a36Sopenharmony_ciput_region:
7362306a36Sopenharmony_ci	omapfb_put_mem_region(rg);
7462306a36Sopenharmony_ciout:
7562306a36Sopenharmony_ci	unlock_fb_info(fbi);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return r ? r : count;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic ssize_t show_mirror(struct device *dev,
8262306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
8562306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", ofbi->mirror);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic ssize_t store_mirror(struct device *dev,
9162306a36Sopenharmony_ci		struct device_attribute *attr,
9262306a36Sopenharmony_ci		const char *buf, size_t count)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
9562306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
9662306a36Sopenharmony_ci	bool mirror;
9762306a36Sopenharmony_ci	int r;
9862306a36Sopenharmony_ci	struct fb_var_screeninfo new_var;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	r = kstrtobool(buf, &mirror);
10162306a36Sopenharmony_ci	if (r)
10262306a36Sopenharmony_ci		return r;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	lock_fb_info(fbi);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	ofbi->mirror = mirror;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	omapfb_get_mem_region(ofbi->region);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	memcpy(&new_var, &fbi->var, sizeof(new_var));
11162306a36Sopenharmony_ci	r = check_fb_var(fbi, &new_var);
11262306a36Sopenharmony_ci	if (r)
11362306a36Sopenharmony_ci		goto out;
11462306a36Sopenharmony_ci	memcpy(&fbi->var, &new_var, sizeof(fbi->var));
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	set_fb_fix(fbi);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	r = omapfb_apply_changes(fbi, 0);
11962306a36Sopenharmony_ci	if (r)
12062306a36Sopenharmony_ci		goto out;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	r = count;
12362306a36Sopenharmony_ciout:
12462306a36Sopenharmony_ci	omapfb_put_mem_region(ofbi->region);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	unlock_fb_info(fbi);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return r;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic ssize_t show_overlays(struct device *dev,
13262306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
13562306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
13662306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
13762306a36Sopenharmony_ci	ssize_t l = 0;
13862306a36Sopenharmony_ci	int t;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	lock_fb_info(fbi);
14162306a36Sopenharmony_ci	omapfb_lock(fbdev);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	for (t = 0; t < ofbi->num_overlays; t++) {
14462306a36Sopenharmony_ci		struct omap_overlay *ovl = ofbi->overlays[t];
14562306a36Sopenharmony_ci		int ovlnum;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
14862306a36Sopenharmony_ci			if (ovl == fbdev->overlays[ovlnum])
14962306a36Sopenharmony_ci				break;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
15262306a36Sopenharmony_ci				t == 0 ? "" : ",", ovlnum);
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	omapfb_unlock(fbdev);
15862306a36Sopenharmony_ci	unlock_fb_info(fbi);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return l;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
16462306a36Sopenharmony_ci		struct omap_overlay *ovl)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	int i, t;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
16962306a36Sopenharmony_ci		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		for (t = 0; t < ofbi->num_overlays; t++) {
17262306a36Sopenharmony_ci			if (ofbi->overlays[t] == ovl)
17362306a36Sopenharmony_ci				return ofbi;
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return NULL;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
18162306a36Sopenharmony_ci		const char *buf, size_t count)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
18462306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
18562306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
18662306a36Sopenharmony_ci	struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
18762306a36Sopenharmony_ci	struct omap_overlay *ovl;
18862306a36Sopenharmony_ci	int num_ovls, r, i;
18962306a36Sopenharmony_ci	int len;
19062306a36Sopenharmony_ci	bool added = false;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	num_ovls = 0;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	len = strlen(buf);
19562306a36Sopenharmony_ci	if (buf[len - 1] == '\n')
19662306a36Sopenharmony_ci		len = len - 1;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	lock_fb_info(fbi);
19962306a36Sopenharmony_ci	omapfb_lock(fbdev);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (len > 0) {
20262306a36Sopenharmony_ci		char *p = (char *)buf;
20362306a36Sopenharmony_ci		int ovlnum;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		while (p < buf + len) {
20662306a36Sopenharmony_ci			int found;
20762306a36Sopenharmony_ci			if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
20862306a36Sopenharmony_ci				r = -EINVAL;
20962306a36Sopenharmony_ci				goto out;
21062306a36Sopenharmony_ci			}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci			ovlnum = simple_strtoul(p, &p, 0);
21362306a36Sopenharmony_ci			if (ovlnum > fbdev->num_overlays) {
21462306a36Sopenharmony_ci				r = -EINVAL;
21562306a36Sopenharmony_ci				goto out;
21662306a36Sopenharmony_ci			}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci			found = 0;
21962306a36Sopenharmony_ci			for (i = 0; i < num_ovls; ++i) {
22062306a36Sopenharmony_ci				if (ovls[i] == fbdev->overlays[ovlnum]) {
22162306a36Sopenharmony_ci					found = 1;
22262306a36Sopenharmony_ci					break;
22362306a36Sopenharmony_ci				}
22462306a36Sopenharmony_ci			}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci			if (!found)
22762306a36Sopenharmony_ci				ovls[num_ovls++] = fbdev->overlays[ovlnum];
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci			p++;
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	for (i = 0; i < num_ovls; ++i) {
23462306a36Sopenharmony_ci		struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
23562306a36Sopenharmony_ci		if (ofbi2 && ofbi2 != ofbi) {
23662306a36Sopenharmony_ci			dev_err(fbdev->dev, "overlay already in use\n");
23762306a36Sopenharmony_ci			r = -EINVAL;
23862306a36Sopenharmony_ci			goto out;
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* detach unused overlays */
24362306a36Sopenharmony_ci	for (i = 0; i < ofbi->num_overlays; ++i) {
24462306a36Sopenharmony_ci		int t, found;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		ovl = ofbi->overlays[i];
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		found = 0;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		for (t = 0; t < num_ovls; ++t) {
25162306a36Sopenharmony_ci			if (ovl == ovls[t]) {
25262306a36Sopenharmony_ci				found = 1;
25362306a36Sopenharmony_ci				break;
25462306a36Sopenharmony_ci			}
25562306a36Sopenharmony_ci		}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		if (found)
25862306a36Sopenharmony_ci			continue;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		DBG("detaching %d\n", ofbi->overlays[i]->id);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		omapfb_get_mem_region(ofbi->region);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		omapfb_overlay_enable(ovl, 0);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		if (ovl->manager)
26762306a36Sopenharmony_ci			ovl->manager->apply(ovl->manager);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		omapfb_put_mem_region(ofbi->region);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci		for (t = i + 1; t < ofbi->num_overlays; t++) {
27262306a36Sopenharmony_ci			ofbi->rotation[t-1] = ofbi->rotation[t];
27362306a36Sopenharmony_ci			ofbi->overlays[t-1] = ofbi->overlays[t];
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		ofbi->num_overlays--;
27762306a36Sopenharmony_ci		i--;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	for (i = 0; i < num_ovls; ++i) {
28162306a36Sopenharmony_ci		int t, found;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		ovl = ovls[i];
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		found = 0;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		for (t = 0; t < ofbi->num_overlays; ++t) {
28862306a36Sopenharmony_ci			if (ovl == ofbi->overlays[t]) {
28962306a36Sopenharmony_ci				found = 1;
29062306a36Sopenharmony_ci				break;
29162306a36Sopenharmony_ci			}
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		if (found)
29562306a36Sopenharmony_ci			continue;
29662306a36Sopenharmony_ci		ofbi->rotation[ofbi->num_overlays] = 0;
29762306a36Sopenharmony_ci		ofbi->overlays[ofbi->num_overlays++] = ovl;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		added = true;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (added) {
30362306a36Sopenharmony_ci		omapfb_get_mem_region(ofbi->region);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		r = omapfb_apply_changes(fbi, 0);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		omapfb_put_mem_region(ofbi->region);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		if (r)
31062306a36Sopenharmony_ci			goto out;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	r = count;
31462306a36Sopenharmony_ciout:
31562306a36Sopenharmony_ci	omapfb_unlock(fbdev);
31662306a36Sopenharmony_ci	unlock_fb_info(fbi);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return r;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic ssize_t show_overlays_rotate(struct device *dev,
32262306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
32562306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
32662306a36Sopenharmony_ci	ssize_t l = 0;
32762306a36Sopenharmony_ci	int t;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	lock_fb_info(fbi);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	for (t = 0; t < ofbi->num_overlays; t++) {
33262306a36Sopenharmony_ci		l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
33362306a36Sopenharmony_ci				t == 0 ? "" : ",", ofbi->rotation[t]);
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	unlock_fb_info(fbi);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return l;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic ssize_t store_overlays_rotate(struct device *dev,
34462306a36Sopenharmony_ci		struct device_attribute *attr, const char *buf, size_t count)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
34762306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
34862306a36Sopenharmony_ci	int num_ovls = 0, r, i;
34962306a36Sopenharmony_ci	int len;
35062306a36Sopenharmony_ci	bool changed = false;
35162306a36Sopenharmony_ci	u8 rotation[OMAPFB_MAX_OVL_PER_FB];
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	len = strlen(buf);
35462306a36Sopenharmony_ci	if (buf[len - 1] == '\n')
35562306a36Sopenharmony_ci		len = len - 1;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	lock_fb_info(fbi);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (len > 0) {
36062306a36Sopenharmony_ci		char *p = (char *)buf;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		while (p < buf + len) {
36362306a36Sopenharmony_ci			int rot;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci			if (num_ovls == ofbi->num_overlays) {
36662306a36Sopenharmony_ci				r = -EINVAL;
36762306a36Sopenharmony_ci				goto out;
36862306a36Sopenharmony_ci			}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci			rot = simple_strtoul(p, &p, 0);
37162306a36Sopenharmony_ci			if (rot < 0 || rot > 3) {
37262306a36Sopenharmony_ci				r = -EINVAL;
37362306a36Sopenharmony_ci				goto out;
37462306a36Sopenharmony_ci			}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci			if (ofbi->rotation[num_ovls] != rot)
37762306a36Sopenharmony_ci				changed = true;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci			rotation[num_ovls++] = rot;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci			p++;
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (num_ovls != ofbi->num_overlays) {
38662306a36Sopenharmony_ci		r = -EINVAL;
38762306a36Sopenharmony_ci		goto out;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (changed) {
39162306a36Sopenharmony_ci		for (i = 0; i < num_ovls; ++i)
39262306a36Sopenharmony_ci			ofbi->rotation[i] = rotation[i];
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		omapfb_get_mem_region(ofbi->region);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		r = omapfb_apply_changes(fbi, 0);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		omapfb_put_mem_region(ofbi->region);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		if (r)
40162306a36Sopenharmony_ci			goto out;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci		/* FIXME error handling? */
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	r = count;
40762306a36Sopenharmony_ciout:
40862306a36Sopenharmony_ci	unlock_fb_info(fbi);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	return r;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic ssize_t show_size(struct device *dev,
41462306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
41762306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return sysfs_emit(buf, "%lu\n", ofbi->region->size);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic ssize_t store_size(struct device *dev, struct device_attribute *attr,
42362306a36Sopenharmony_ci		const char *buf, size_t count)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
42662306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
42762306a36Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
42862306a36Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
42962306a36Sopenharmony_ci	struct omapfb2_mem_region *rg;
43062306a36Sopenharmony_ci	unsigned long size;
43162306a36Sopenharmony_ci	int r;
43262306a36Sopenharmony_ci	int i;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	r = kstrtoul(buf, 0, &size);
43562306a36Sopenharmony_ci	if (r)
43662306a36Sopenharmony_ci		return r;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	size = PAGE_ALIGN(size);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	lock_fb_info(fbi);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (display && display->driver->sync)
44362306a36Sopenharmony_ci		display->driver->sync(display);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	rg = ofbi->region;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	down_write_nested(&rg->lock, rg->id);
44862306a36Sopenharmony_ci	atomic_inc(&rg->lock_count);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (atomic_read(&rg->map_count)) {
45162306a36Sopenharmony_ci		r = -EBUSY;
45262306a36Sopenharmony_ci		goto out;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
45662306a36Sopenharmony_ci		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
45762306a36Sopenharmony_ci		int j;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		if (ofbi2->region != rg)
46062306a36Sopenharmony_ci			continue;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		for (j = 0; j < ofbi2->num_overlays; j++) {
46362306a36Sopenharmony_ci			struct omap_overlay *ovl;
46462306a36Sopenharmony_ci			ovl = ofbi2->overlays[j];
46562306a36Sopenharmony_ci			if (ovl->is_enabled(ovl)) {
46662306a36Sopenharmony_ci				r = -EBUSY;
46762306a36Sopenharmony_ci				goto out;
46862306a36Sopenharmony_ci			}
46962306a36Sopenharmony_ci		}
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (size != ofbi->region->size) {
47362306a36Sopenharmony_ci		r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
47462306a36Sopenharmony_ci		if (r) {
47562306a36Sopenharmony_ci			dev_err(dev, "realloc fbmem failed\n");
47662306a36Sopenharmony_ci			goto out;
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	r = count;
48162306a36Sopenharmony_ciout:
48262306a36Sopenharmony_ci	atomic_dec(&rg->lock_count);
48362306a36Sopenharmony_ci	up_write(&rg->lock);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	unlock_fb_info(fbi);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return r;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic ssize_t show_phys(struct device *dev,
49162306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
49462306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	return sysfs_emit(buf, "%0x\n", ofbi->region->paddr);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic ssize_t show_virt(struct device *dev,
50062306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
50362306a36Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	return sysfs_emit(buf, "%p\n", ofbi->region->vaddr);
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic ssize_t show_upd_mode(struct device *dev,
50962306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
51262306a36Sopenharmony_ci	enum omapfb_update_mode mode;
51362306a36Sopenharmony_ci	int r;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	r = omapfb_get_update_mode(fbi, &mode);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (r)
51862306a36Sopenharmony_ci		return r;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", (unsigned int)mode);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
52462306a36Sopenharmony_ci		const char *buf, size_t count)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
52762306a36Sopenharmony_ci	unsigned mode;
52862306a36Sopenharmony_ci	int r;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	r = kstrtouint(buf, 0, &mode);
53162306a36Sopenharmony_ci	if (r)
53262306a36Sopenharmony_ci		return r;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	r = omapfb_set_update_mode(fbi, mode);
53562306a36Sopenharmony_ci	if (r)
53662306a36Sopenharmony_ci		return r;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return count;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic struct device_attribute omapfb_attrs[] = {
54262306a36Sopenharmony_ci	__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
54362306a36Sopenharmony_ci			store_rotate_type),
54462306a36Sopenharmony_ci	__ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
54562306a36Sopenharmony_ci	__ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
54662306a36Sopenharmony_ci	__ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
54762306a36Sopenharmony_ci	__ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
54862306a36Sopenharmony_ci			store_overlays_rotate),
54962306a36Sopenharmony_ci	__ATTR(phys_addr, S_IRUGO, show_phys, NULL),
55062306a36Sopenharmony_ci	__ATTR(virt_addr, S_IRUGO, show_virt, NULL),
55162306a36Sopenharmony_ci	__ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
55262306a36Sopenharmony_ci};
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ciint omapfb_create_sysfs(struct omapfb2_device *fbdev)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	int i;
55762306a36Sopenharmony_ci	int r;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	DBG("create sysfs for fbs\n");
56062306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
56162306a36Sopenharmony_ci		int t;
56262306a36Sopenharmony_ci		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
56362306a36Sopenharmony_ci			r = device_create_file(fbdev->fbs[i]->dev,
56462306a36Sopenharmony_ci					&omapfb_attrs[t]);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci			if (r) {
56762306a36Sopenharmony_ci				dev_err(fbdev->dev, "failed to create sysfs "
56862306a36Sopenharmony_ci						"file\n");
56962306a36Sopenharmony_ci				return r;
57062306a36Sopenharmony_ci			}
57162306a36Sopenharmony_ci		}
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	return 0;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_civoid omapfb_remove_sysfs(struct omapfb2_device *fbdev)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	int i, t;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	DBG("remove sysfs for fbs\n");
58262306a36Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
58362306a36Sopenharmony_ci		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
58462306a36Sopenharmony_ci			device_remove_file(fbdev->fbs[i]->dev,
58562306a36Sopenharmony_ci					&omapfb_attrs[t]);
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
589