18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/drivers/video/omap2/omapfb-sysfs.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation
68c2ecf20Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Some code and ideas taken from drivers/video/omap/ driver
98c2ecf20Sopenharmony_ci * by Imre Deak.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/fb.h>
138c2ecf20Sopenharmony_ci#include <linux/sysfs.h>
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/kernel.h>
188c2ecf20Sopenharmony_ci#include <linux/mm.h>
198c2ecf20Sopenharmony_ci#include <linux/omapfb.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <video/omapfb_dss.h>
228c2ecf20Sopenharmony_ci#include <video/omapvrfb.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "omapfb.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic ssize_t show_rotate_type(struct device *dev,
278c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
308c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic ssize_t store_rotate_type(struct device *dev,
368c2ecf20Sopenharmony_ci		struct device_attribute *attr,
378c2ecf20Sopenharmony_ci		const char *buf, size_t count)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
408c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
418c2ecf20Sopenharmony_ci	struct omapfb2_mem_region *rg;
428c2ecf20Sopenharmony_ci	int rot_type;
438c2ecf20Sopenharmony_ci	int r;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	r = kstrtoint(buf, 0, &rot_type);
468c2ecf20Sopenharmony_ci	if (r)
478c2ecf20Sopenharmony_ci		return r;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
508c2ecf20Sopenharmony_ci		return -EINVAL;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	lock_fb_info(fbi);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	r = 0;
558c2ecf20Sopenharmony_ci	if (rot_type == ofbi->rotation_type)
568c2ecf20Sopenharmony_ci		goto out;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	rg = omapfb_get_mem_region(ofbi->region);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (rg->size) {
618c2ecf20Sopenharmony_ci		r = -EBUSY;
628c2ecf20Sopenharmony_ci		goto put_region;
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	ofbi->rotation_type = rot_type;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/*
688c2ecf20Sopenharmony_ci	 * Since the VRAM for this FB is not allocated at the moment we don't
698c2ecf20Sopenharmony_ci	 * need to do any further parameter checking at this point.
708c2ecf20Sopenharmony_ci	 */
718c2ecf20Sopenharmony_ciput_region:
728c2ecf20Sopenharmony_ci	omapfb_put_mem_region(rg);
738c2ecf20Sopenharmony_ciout:
748c2ecf20Sopenharmony_ci	unlock_fb_info(fbi);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return r ? r : count;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic ssize_t show_mirror(struct device *dev,
818c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
848c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic ssize_t store_mirror(struct device *dev,
908c2ecf20Sopenharmony_ci		struct device_attribute *attr,
918c2ecf20Sopenharmony_ci		const char *buf, size_t count)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
948c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
958c2ecf20Sopenharmony_ci	bool mirror;
968c2ecf20Sopenharmony_ci	int r;
978c2ecf20Sopenharmony_ci	struct fb_var_screeninfo new_var;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	r = strtobool(buf, &mirror);
1008c2ecf20Sopenharmony_ci	if (r)
1018c2ecf20Sopenharmony_ci		return r;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	lock_fb_info(fbi);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	ofbi->mirror = mirror;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	omapfb_get_mem_region(ofbi->region);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	memcpy(&new_var, &fbi->var, sizeof(new_var));
1108c2ecf20Sopenharmony_ci	r = check_fb_var(fbi, &new_var);
1118c2ecf20Sopenharmony_ci	if (r)
1128c2ecf20Sopenharmony_ci		goto out;
1138c2ecf20Sopenharmony_ci	memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	set_fb_fix(fbi);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	r = omapfb_apply_changes(fbi, 0);
1188c2ecf20Sopenharmony_ci	if (r)
1198c2ecf20Sopenharmony_ci		goto out;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	r = count;
1228c2ecf20Sopenharmony_ciout:
1238c2ecf20Sopenharmony_ci	omapfb_put_mem_region(ofbi->region);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	unlock_fb_info(fbi);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return r;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic ssize_t show_overlays(struct device *dev,
1318c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
1348c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
1358c2ecf20Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
1368c2ecf20Sopenharmony_ci	ssize_t l = 0;
1378c2ecf20Sopenharmony_ci	int t;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	lock_fb_info(fbi);
1408c2ecf20Sopenharmony_ci	omapfb_lock(fbdev);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	for (t = 0; t < ofbi->num_overlays; t++) {
1438c2ecf20Sopenharmony_ci		struct omap_overlay *ovl = ofbi->overlays[t];
1448c2ecf20Sopenharmony_ci		int ovlnum;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci		for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
1478c2ecf20Sopenharmony_ci			if (ovl == fbdev->overlays[ovlnum])
1488c2ecf20Sopenharmony_ci				break;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci		l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
1518c2ecf20Sopenharmony_ci				t == 0 ? "" : ",", ovlnum);
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	omapfb_unlock(fbdev);
1578c2ecf20Sopenharmony_ci	unlock_fb_info(fbi);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	return l;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
1638c2ecf20Sopenharmony_ci		struct omap_overlay *ovl)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	int i, t;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
1688c2ecf20Sopenharmony_ci		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci		for (t = 0; t < ofbi->num_overlays; t++) {
1718c2ecf20Sopenharmony_ci			if (ofbi->overlays[t] == ovl)
1728c2ecf20Sopenharmony_ci				return ofbi;
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	return NULL;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
1808c2ecf20Sopenharmony_ci		const char *buf, size_t count)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
1838c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
1848c2ecf20Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
1858c2ecf20Sopenharmony_ci	struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
1868c2ecf20Sopenharmony_ci	struct omap_overlay *ovl;
1878c2ecf20Sopenharmony_ci	int num_ovls, r, i;
1888c2ecf20Sopenharmony_ci	int len;
1898c2ecf20Sopenharmony_ci	bool added = false;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	num_ovls = 0;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	len = strlen(buf);
1948c2ecf20Sopenharmony_ci	if (buf[len - 1] == '\n')
1958c2ecf20Sopenharmony_ci		len = len - 1;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	lock_fb_info(fbi);
1988c2ecf20Sopenharmony_ci	omapfb_lock(fbdev);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (len > 0) {
2018c2ecf20Sopenharmony_ci		char *p = (char *)buf;
2028c2ecf20Sopenharmony_ci		int ovlnum;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		while (p < buf + len) {
2058c2ecf20Sopenharmony_ci			int found;
2068c2ecf20Sopenharmony_ci			if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
2078c2ecf20Sopenharmony_ci				r = -EINVAL;
2088c2ecf20Sopenharmony_ci				goto out;
2098c2ecf20Sopenharmony_ci			}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci			ovlnum = simple_strtoul(p, &p, 0);
2128c2ecf20Sopenharmony_ci			if (ovlnum > fbdev->num_overlays) {
2138c2ecf20Sopenharmony_ci				r = -EINVAL;
2148c2ecf20Sopenharmony_ci				goto out;
2158c2ecf20Sopenharmony_ci			}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci			found = 0;
2188c2ecf20Sopenharmony_ci			for (i = 0; i < num_ovls; ++i) {
2198c2ecf20Sopenharmony_ci				if (ovls[i] == fbdev->overlays[ovlnum]) {
2208c2ecf20Sopenharmony_ci					found = 1;
2218c2ecf20Sopenharmony_ci					break;
2228c2ecf20Sopenharmony_ci				}
2238c2ecf20Sopenharmony_ci			}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci			if (!found)
2268c2ecf20Sopenharmony_ci				ovls[num_ovls++] = fbdev->overlays[ovlnum];
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci			p++;
2298c2ecf20Sopenharmony_ci		}
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	for (i = 0; i < num_ovls; ++i) {
2338c2ecf20Sopenharmony_ci		struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
2348c2ecf20Sopenharmony_ci		if (ofbi2 && ofbi2 != ofbi) {
2358c2ecf20Sopenharmony_ci			dev_err(fbdev->dev, "overlay already in use\n");
2368c2ecf20Sopenharmony_ci			r = -EINVAL;
2378c2ecf20Sopenharmony_ci			goto out;
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* detach unused overlays */
2428c2ecf20Sopenharmony_ci	for (i = 0; i < ofbi->num_overlays; ++i) {
2438c2ecf20Sopenharmony_ci		int t, found;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		ovl = ofbi->overlays[i];
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		found = 0;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		for (t = 0; t < num_ovls; ++t) {
2508c2ecf20Sopenharmony_ci			if (ovl == ovls[t]) {
2518c2ecf20Sopenharmony_ci				found = 1;
2528c2ecf20Sopenharmony_ci				break;
2538c2ecf20Sopenharmony_ci			}
2548c2ecf20Sopenharmony_ci		}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci		if (found)
2578c2ecf20Sopenharmony_ci			continue;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		DBG("detaching %d\n", ofbi->overlays[i]->id);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		omapfb_get_mem_region(ofbi->region);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		omapfb_overlay_enable(ovl, 0);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		if (ovl->manager)
2668c2ecf20Sopenharmony_ci			ovl->manager->apply(ovl->manager);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci		omapfb_put_mem_region(ofbi->region);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		for (t = i + 1; t < ofbi->num_overlays; t++) {
2718c2ecf20Sopenharmony_ci			ofbi->rotation[t-1] = ofbi->rotation[t];
2728c2ecf20Sopenharmony_ci			ofbi->overlays[t-1] = ofbi->overlays[t];
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		ofbi->num_overlays--;
2768c2ecf20Sopenharmony_ci		i--;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	for (i = 0; i < num_ovls; ++i) {
2808c2ecf20Sopenharmony_ci		int t, found;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		ovl = ovls[i];
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		found = 0;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		for (t = 0; t < ofbi->num_overlays; ++t) {
2878c2ecf20Sopenharmony_ci			if (ovl == ofbi->overlays[t]) {
2888c2ecf20Sopenharmony_ci				found = 1;
2898c2ecf20Sopenharmony_ci				break;
2908c2ecf20Sopenharmony_ci			}
2918c2ecf20Sopenharmony_ci		}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci		if (found)
2948c2ecf20Sopenharmony_ci			continue;
2958c2ecf20Sopenharmony_ci		ofbi->rotation[ofbi->num_overlays] = 0;
2968c2ecf20Sopenharmony_ci		ofbi->overlays[ofbi->num_overlays++] = ovl;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci		added = true;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (added) {
3028c2ecf20Sopenharmony_ci		omapfb_get_mem_region(ofbi->region);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		r = omapfb_apply_changes(fbi, 0);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		omapfb_put_mem_region(ofbi->region);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		if (r)
3098c2ecf20Sopenharmony_ci			goto out;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	r = count;
3138c2ecf20Sopenharmony_ciout:
3148c2ecf20Sopenharmony_ci	omapfb_unlock(fbdev);
3158c2ecf20Sopenharmony_ci	unlock_fb_info(fbi);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return r;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic ssize_t show_overlays_rotate(struct device *dev,
3218c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
3248c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
3258c2ecf20Sopenharmony_ci	ssize_t l = 0;
3268c2ecf20Sopenharmony_ci	int t;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	lock_fb_info(fbi);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	for (t = 0; t < ofbi->num_overlays; t++) {
3318c2ecf20Sopenharmony_ci		l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
3328c2ecf20Sopenharmony_ci				t == 0 ? "" : ",", ofbi->rotation[t]);
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	unlock_fb_info(fbi);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return l;
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic ssize_t store_overlays_rotate(struct device *dev,
3438c2ecf20Sopenharmony_ci		struct device_attribute *attr, const char *buf, size_t count)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
3468c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
3478c2ecf20Sopenharmony_ci	int num_ovls = 0, r, i;
3488c2ecf20Sopenharmony_ci	int len;
3498c2ecf20Sopenharmony_ci	bool changed = false;
3508c2ecf20Sopenharmony_ci	u8 rotation[OMAPFB_MAX_OVL_PER_FB];
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	len = strlen(buf);
3538c2ecf20Sopenharmony_ci	if (buf[len - 1] == '\n')
3548c2ecf20Sopenharmony_ci		len = len - 1;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	lock_fb_info(fbi);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (len > 0) {
3598c2ecf20Sopenharmony_ci		char *p = (char *)buf;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		while (p < buf + len) {
3628c2ecf20Sopenharmony_ci			int rot;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci			if (num_ovls == ofbi->num_overlays) {
3658c2ecf20Sopenharmony_ci				r = -EINVAL;
3668c2ecf20Sopenharmony_ci				goto out;
3678c2ecf20Sopenharmony_ci			}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci			rot = simple_strtoul(p, &p, 0);
3708c2ecf20Sopenharmony_ci			if (rot < 0 || rot > 3) {
3718c2ecf20Sopenharmony_ci				r = -EINVAL;
3728c2ecf20Sopenharmony_ci				goto out;
3738c2ecf20Sopenharmony_ci			}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci			if (ofbi->rotation[num_ovls] != rot)
3768c2ecf20Sopenharmony_ci				changed = true;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci			rotation[num_ovls++] = rot;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci			p++;
3818c2ecf20Sopenharmony_ci		}
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (num_ovls != ofbi->num_overlays) {
3858c2ecf20Sopenharmony_ci		r = -EINVAL;
3868c2ecf20Sopenharmony_ci		goto out;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (changed) {
3908c2ecf20Sopenharmony_ci		for (i = 0; i < num_ovls; ++i)
3918c2ecf20Sopenharmony_ci			ofbi->rotation[i] = rotation[i];
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		omapfb_get_mem_region(ofbi->region);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		r = omapfb_apply_changes(fbi, 0);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		omapfb_put_mem_region(ofbi->region);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		if (r)
4008c2ecf20Sopenharmony_ci			goto out;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		/* FIXME error handling? */
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	r = count;
4068c2ecf20Sopenharmony_ciout:
4078c2ecf20Sopenharmony_ci	unlock_fb_info(fbi);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return r;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic ssize_t show_size(struct device *dev,
4138c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
4168c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic ssize_t store_size(struct device *dev, struct device_attribute *attr,
4228c2ecf20Sopenharmony_ci		const char *buf, size_t count)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
4258c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
4268c2ecf20Sopenharmony_ci	struct omapfb2_device *fbdev = ofbi->fbdev;
4278c2ecf20Sopenharmony_ci	struct omap_dss_device *display = fb2display(fbi);
4288c2ecf20Sopenharmony_ci	struct omapfb2_mem_region *rg;
4298c2ecf20Sopenharmony_ci	unsigned long size;
4308c2ecf20Sopenharmony_ci	int r;
4318c2ecf20Sopenharmony_ci	int i;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	r = kstrtoul(buf, 0, &size);
4348c2ecf20Sopenharmony_ci	if (r)
4358c2ecf20Sopenharmony_ci		return r;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	size = PAGE_ALIGN(size);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	lock_fb_info(fbi);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (display && display->driver->sync)
4428c2ecf20Sopenharmony_ci		display->driver->sync(display);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	rg = ofbi->region;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	down_write_nested(&rg->lock, rg->id);
4478c2ecf20Sopenharmony_ci	atomic_inc(&rg->lock_count);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	if (atomic_read(&rg->map_count)) {
4508c2ecf20Sopenharmony_ci		r = -EBUSY;
4518c2ecf20Sopenharmony_ci		goto out;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
4558c2ecf20Sopenharmony_ci		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
4568c2ecf20Sopenharmony_ci		int j;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		if (ofbi2->region != rg)
4598c2ecf20Sopenharmony_ci			continue;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		for (j = 0; j < ofbi2->num_overlays; j++) {
4628c2ecf20Sopenharmony_ci			struct omap_overlay *ovl;
4638c2ecf20Sopenharmony_ci			ovl = ofbi2->overlays[j];
4648c2ecf20Sopenharmony_ci			if (ovl->is_enabled(ovl)) {
4658c2ecf20Sopenharmony_ci				r = -EBUSY;
4668c2ecf20Sopenharmony_ci				goto out;
4678c2ecf20Sopenharmony_ci			}
4688c2ecf20Sopenharmony_ci		}
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (size != ofbi->region->size) {
4728c2ecf20Sopenharmony_ci		r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
4738c2ecf20Sopenharmony_ci		if (r) {
4748c2ecf20Sopenharmony_ci			dev_err(dev, "realloc fbmem failed\n");
4758c2ecf20Sopenharmony_ci			goto out;
4768c2ecf20Sopenharmony_ci		}
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	r = count;
4808c2ecf20Sopenharmony_ciout:
4818c2ecf20Sopenharmony_ci	atomic_dec(&rg->lock_count);
4828c2ecf20Sopenharmony_ci	up_write(&rg->lock);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	unlock_fb_info(fbi);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	return r;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_cistatic ssize_t show_phys(struct device *dev,
4908c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
4938c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic ssize_t show_virt(struct device *dev,
4998c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
5028c2ecf20Sopenharmony_ci	struct omapfb_info *ofbi = FB2OFB(fbi);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic ssize_t show_upd_mode(struct device *dev,
5088c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
5118c2ecf20Sopenharmony_ci	enum omapfb_update_mode mode;
5128c2ecf20Sopenharmony_ci	int r;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	r = omapfb_get_update_mode(fbi, &mode);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (r)
5178c2ecf20Sopenharmony_ci		return r;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
5238c2ecf20Sopenharmony_ci		const char *buf, size_t count)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	struct fb_info *fbi = dev_get_drvdata(dev);
5268c2ecf20Sopenharmony_ci	unsigned mode;
5278c2ecf20Sopenharmony_ci	int r;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	r = kstrtouint(buf, 0, &mode);
5308c2ecf20Sopenharmony_ci	if (r)
5318c2ecf20Sopenharmony_ci		return r;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	r = omapfb_set_update_mode(fbi, mode);
5348c2ecf20Sopenharmony_ci	if (r)
5358c2ecf20Sopenharmony_ci		return r;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	return count;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic struct device_attribute omapfb_attrs[] = {
5418c2ecf20Sopenharmony_ci	__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
5428c2ecf20Sopenharmony_ci			store_rotate_type),
5438c2ecf20Sopenharmony_ci	__ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
5448c2ecf20Sopenharmony_ci	__ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
5458c2ecf20Sopenharmony_ci	__ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
5468c2ecf20Sopenharmony_ci	__ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
5478c2ecf20Sopenharmony_ci			store_overlays_rotate),
5488c2ecf20Sopenharmony_ci	__ATTR(phys_addr, S_IRUGO, show_phys, NULL),
5498c2ecf20Sopenharmony_ci	__ATTR(virt_addr, S_IRUGO, show_virt, NULL),
5508c2ecf20Sopenharmony_ci	__ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
5518c2ecf20Sopenharmony_ci};
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ciint omapfb_create_sysfs(struct omapfb2_device *fbdev)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	int i;
5568c2ecf20Sopenharmony_ci	int r;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	DBG("create sysfs for fbs\n");
5598c2ecf20Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
5608c2ecf20Sopenharmony_ci		int t;
5618c2ecf20Sopenharmony_ci		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
5628c2ecf20Sopenharmony_ci			r = device_create_file(fbdev->fbs[i]->dev,
5638c2ecf20Sopenharmony_ci					&omapfb_attrs[t]);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci			if (r) {
5668c2ecf20Sopenharmony_ci				dev_err(fbdev->dev, "failed to create sysfs "
5678c2ecf20Sopenharmony_ci						"file\n");
5688c2ecf20Sopenharmony_ci				return r;
5698c2ecf20Sopenharmony_ci			}
5708c2ecf20Sopenharmony_ci		}
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	return 0;
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_civoid omapfb_remove_sysfs(struct omapfb2_device *fbdev)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	int i, t;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	DBG("remove sysfs for fbs\n");
5818c2ecf20Sopenharmony_ci	for (i = 0; i < fbdev->num_fbs; i++) {
5828c2ecf20Sopenharmony_ci		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
5838c2ecf20Sopenharmony_ci			device_remove_file(fbdev->fbs[i]->dev,
5848c2ecf20Sopenharmony_ci					&omapfb_attrs[t]);
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
588