xref: /OK3568_Linux_fs/kernel/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * linux/drivers/video/omap2/omapfb-sysfs.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2008 Nokia Corporation
6*4882a593Smuzhiyun  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Some code and ideas taken from drivers/video/omap/ driver
9*4882a593Smuzhiyun  * by Imre Deak.
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/fb.h>
13*4882a593Smuzhiyun #include <linux/sysfs.h>
14*4882a593Smuzhiyun #include <linux/device.h>
15*4882a593Smuzhiyun #include <linux/uaccess.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/kernel.h>
18*4882a593Smuzhiyun #include <linux/mm.h>
19*4882a593Smuzhiyun #include <linux/omapfb.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include <video/omapfb_dss.h>
22*4882a593Smuzhiyun #include <video/omapvrfb.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include "omapfb.h"
25*4882a593Smuzhiyun 
show_rotate_type(struct device * dev,struct device_attribute * attr,char * buf)26*4882a593Smuzhiyun static ssize_t show_rotate_type(struct device *dev,
27*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
30*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun 
store_rotate_type(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)35*4882a593Smuzhiyun static ssize_t store_rotate_type(struct device *dev,
36*4882a593Smuzhiyun 		struct device_attribute *attr,
37*4882a593Smuzhiyun 		const char *buf, size_t count)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
40*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
41*4882a593Smuzhiyun 	struct omapfb2_mem_region *rg;
42*4882a593Smuzhiyun 	int rot_type;
43*4882a593Smuzhiyun 	int r;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	r = kstrtoint(buf, 0, &rot_type);
46*4882a593Smuzhiyun 	if (r)
47*4882a593Smuzhiyun 		return r;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
50*4882a593Smuzhiyun 		return -EINVAL;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	lock_fb_info(fbi);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	r = 0;
55*4882a593Smuzhiyun 	if (rot_type == ofbi->rotation_type)
56*4882a593Smuzhiyun 		goto out;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	rg = omapfb_get_mem_region(ofbi->region);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	if (rg->size) {
61*4882a593Smuzhiyun 		r = -EBUSY;
62*4882a593Smuzhiyun 		goto put_region;
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	ofbi->rotation_type = rot_type;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	/*
68*4882a593Smuzhiyun 	 * Since the VRAM for this FB is not allocated at the moment we don't
69*4882a593Smuzhiyun 	 * need to do any further parameter checking at this point.
70*4882a593Smuzhiyun 	 */
71*4882a593Smuzhiyun put_region:
72*4882a593Smuzhiyun 	omapfb_put_mem_region(rg);
73*4882a593Smuzhiyun out:
74*4882a593Smuzhiyun 	unlock_fb_info(fbi);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	return r ? r : count;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 
show_mirror(struct device * dev,struct device_attribute * attr,char * buf)80*4882a593Smuzhiyun static ssize_t show_mirror(struct device *dev,
81*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
84*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
store_mirror(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)89*4882a593Smuzhiyun static ssize_t store_mirror(struct device *dev,
90*4882a593Smuzhiyun 		struct device_attribute *attr,
91*4882a593Smuzhiyun 		const char *buf, size_t count)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
94*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
95*4882a593Smuzhiyun 	bool mirror;
96*4882a593Smuzhiyun 	int r;
97*4882a593Smuzhiyun 	struct fb_var_screeninfo new_var;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	r = strtobool(buf, &mirror);
100*4882a593Smuzhiyun 	if (r)
101*4882a593Smuzhiyun 		return r;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	lock_fb_info(fbi);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	ofbi->mirror = mirror;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	omapfb_get_mem_region(ofbi->region);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	memcpy(&new_var, &fbi->var, sizeof(new_var));
110*4882a593Smuzhiyun 	r = check_fb_var(fbi, &new_var);
111*4882a593Smuzhiyun 	if (r)
112*4882a593Smuzhiyun 		goto out;
113*4882a593Smuzhiyun 	memcpy(&fbi->var, &new_var, sizeof(fbi->var));
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	set_fb_fix(fbi);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	r = omapfb_apply_changes(fbi, 0);
118*4882a593Smuzhiyun 	if (r)
119*4882a593Smuzhiyun 		goto out;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	r = count;
122*4882a593Smuzhiyun out:
123*4882a593Smuzhiyun 	omapfb_put_mem_region(ofbi->region);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	unlock_fb_info(fbi);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	return r;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
show_overlays(struct device * dev,struct device_attribute * attr,char * buf)130*4882a593Smuzhiyun static ssize_t show_overlays(struct device *dev,
131*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
134*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
135*4882a593Smuzhiyun 	struct omapfb2_device *fbdev = ofbi->fbdev;
136*4882a593Smuzhiyun 	ssize_t l = 0;
137*4882a593Smuzhiyun 	int t;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	lock_fb_info(fbi);
140*4882a593Smuzhiyun 	omapfb_lock(fbdev);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	for (t = 0; t < ofbi->num_overlays; t++) {
143*4882a593Smuzhiyun 		struct omap_overlay *ovl = ofbi->overlays[t];
144*4882a593Smuzhiyun 		int ovlnum;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 		for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
147*4882a593Smuzhiyun 			if (ovl == fbdev->overlays[ovlnum])
148*4882a593Smuzhiyun 				break;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 		l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
151*4882a593Smuzhiyun 				t == 0 ? "" : ",", ovlnum);
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	omapfb_unlock(fbdev);
157*4882a593Smuzhiyun 	unlock_fb_info(fbi);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	return l;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
get_overlay_fb(struct omapfb2_device * fbdev,struct omap_overlay * ovl)162*4882a593Smuzhiyun static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
163*4882a593Smuzhiyun 		struct omap_overlay *ovl)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	int i, t;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	for (i = 0; i < fbdev->num_fbs; i++) {
168*4882a593Smuzhiyun 		struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 		for (t = 0; t < ofbi->num_overlays; t++) {
171*4882a593Smuzhiyun 			if (ofbi->overlays[t] == ovl)
172*4882a593Smuzhiyun 				return ofbi;
173*4882a593Smuzhiyun 		}
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	return NULL;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
store_overlays(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)179*4882a593Smuzhiyun static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
180*4882a593Smuzhiyun 		const char *buf, size_t count)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
183*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
184*4882a593Smuzhiyun 	struct omapfb2_device *fbdev = ofbi->fbdev;
185*4882a593Smuzhiyun 	struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
186*4882a593Smuzhiyun 	struct omap_overlay *ovl;
187*4882a593Smuzhiyun 	int num_ovls, r, i;
188*4882a593Smuzhiyun 	int len;
189*4882a593Smuzhiyun 	bool added = false;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	num_ovls = 0;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	len = strlen(buf);
194*4882a593Smuzhiyun 	if (buf[len - 1] == '\n')
195*4882a593Smuzhiyun 		len = len - 1;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	lock_fb_info(fbi);
198*4882a593Smuzhiyun 	omapfb_lock(fbdev);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	if (len > 0) {
201*4882a593Smuzhiyun 		char *p = (char *)buf;
202*4882a593Smuzhiyun 		int ovlnum;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 		while (p < buf + len) {
205*4882a593Smuzhiyun 			int found;
206*4882a593Smuzhiyun 			if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
207*4882a593Smuzhiyun 				r = -EINVAL;
208*4882a593Smuzhiyun 				goto out;
209*4882a593Smuzhiyun 			}
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 			ovlnum = simple_strtoul(p, &p, 0);
212*4882a593Smuzhiyun 			if (ovlnum > fbdev->num_overlays) {
213*4882a593Smuzhiyun 				r = -EINVAL;
214*4882a593Smuzhiyun 				goto out;
215*4882a593Smuzhiyun 			}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 			found = 0;
218*4882a593Smuzhiyun 			for (i = 0; i < num_ovls; ++i) {
219*4882a593Smuzhiyun 				if (ovls[i] == fbdev->overlays[ovlnum]) {
220*4882a593Smuzhiyun 					found = 1;
221*4882a593Smuzhiyun 					break;
222*4882a593Smuzhiyun 				}
223*4882a593Smuzhiyun 			}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 			if (!found)
226*4882a593Smuzhiyun 				ovls[num_ovls++] = fbdev->overlays[ovlnum];
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 			p++;
229*4882a593Smuzhiyun 		}
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	for (i = 0; i < num_ovls; ++i) {
233*4882a593Smuzhiyun 		struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
234*4882a593Smuzhiyun 		if (ofbi2 && ofbi2 != ofbi) {
235*4882a593Smuzhiyun 			dev_err(fbdev->dev, "overlay already in use\n");
236*4882a593Smuzhiyun 			r = -EINVAL;
237*4882a593Smuzhiyun 			goto out;
238*4882a593Smuzhiyun 		}
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	/* detach unused overlays */
242*4882a593Smuzhiyun 	for (i = 0; i < ofbi->num_overlays; ++i) {
243*4882a593Smuzhiyun 		int t, found;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 		ovl = ofbi->overlays[i];
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 		found = 0;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 		for (t = 0; t < num_ovls; ++t) {
250*4882a593Smuzhiyun 			if (ovl == ovls[t]) {
251*4882a593Smuzhiyun 				found = 1;
252*4882a593Smuzhiyun 				break;
253*4882a593Smuzhiyun 			}
254*4882a593Smuzhiyun 		}
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 		if (found)
257*4882a593Smuzhiyun 			continue;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 		DBG("detaching %d\n", ofbi->overlays[i]->id);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 		omapfb_get_mem_region(ofbi->region);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 		omapfb_overlay_enable(ovl, 0);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 		if (ovl->manager)
266*4882a593Smuzhiyun 			ovl->manager->apply(ovl->manager);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 		omapfb_put_mem_region(ofbi->region);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 		for (t = i + 1; t < ofbi->num_overlays; t++) {
271*4882a593Smuzhiyun 			ofbi->rotation[t-1] = ofbi->rotation[t];
272*4882a593Smuzhiyun 			ofbi->overlays[t-1] = ofbi->overlays[t];
273*4882a593Smuzhiyun 		}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		ofbi->num_overlays--;
276*4882a593Smuzhiyun 		i--;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	for (i = 0; i < num_ovls; ++i) {
280*4882a593Smuzhiyun 		int t, found;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 		ovl = ovls[i];
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 		found = 0;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 		for (t = 0; t < ofbi->num_overlays; ++t) {
287*4882a593Smuzhiyun 			if (ovl == ofbi->overlays[t]) {
288*4882a593Smuzhiyun 				found = 1;
289*4882a593Smuzhiyun 				break;
290*4882a593Smuzhiyun 			}
291*4882a593Smuzhiyun 		}
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 		if (found)
294*4882a593Smuzhiyun 			continue;
295*4882a593Smuzhiyun 		ofbi->rotation[ofbi->num_overlays] = 0;
296*4882a593Smuzhiyun 		ofbi->overlays[ofbi->num_overlays++] = ovl;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 		added = true;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	if (added) {
302*4882a593Smuzhiyun 		omapfb_get_mem_region(ofbi->region);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		r = omapfb_apply_changes(fbi, 0);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 		omapfb_put_mem_region(ofbi->region);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		if (r)
309*4882a593Smuzhiyun 			goto out;
310*4882a593Smuzhiyun 	}
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	r = count;
313*4882a593Smuzhiyun out:
314*4882a593Smuzhiyun 	omapfb_unlock(fbdev);
315*4882a593Smuzhiyun 	unlock_fb_info(fbi);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	return r;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
show_overlays_rotate(struct device * dev,struct device_attribute * attr,char * buf)320*4882a593Smuzhiyun static ssize_t show_overlays_rotate(struct device *dev,
321*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
324*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
325*4882a593Smuzhiyun 	ssize_t l = 0;
326*4882a593Smuzhiyun 	int t;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	lock_fb_info(fbi);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	for (t = 0; t < ofbi->num_overlays; t++) {
331*4882a593Smuzhiyun 		l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
332*4882a593Smuzhiyun 				t == 0 ? "" : ",", ofbi->rotation[t]);
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	unlock_fb_info(fbi);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	return l;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
store_overlays_rotate(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)342*4882a593Smuzhiyun static ssize_t store_overlays_rotate(struct device *dev,
343*4882a593Smuzhiyun 		struct device_attribute *attr, const char *buf, size_t count)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
346*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
347*4882a593Smuzhiyun 	int num_ovls = 0, r, i;
348*4882a593Smuzhiyun 	int len;
349*4882a593Smuzhiyun 	bool changed = false;
350*4882a593Smuzhiyun 	u8 rotation[OMAPFB_MAX_OVL_PER_FB];
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	len = strlen(buf);
353*4882a593Smuzhiyun 	if (buf[len - 1] == '\n')
354*4882a593Smuzhiyun 		len = len - 1;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	lock_fb_info(fbi);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	if (len > 0) {
359*4882a593Smuzhiyun 		char *p = (char *)buf;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 		while (p < buf + len) {
362*4882a593Smuzhiyun 			int rot;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 			if (num_ovls == ofbi->num_overlays) {
365*4882a593Smuzhiyun 				r = -EINVAL;
366*4882a593Smuzhiyun 				goto out;
367*4882a593Smuzhiyun 			}
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 			rot = simple_strtoul(p, &p, 0);
370*4882a593Smuzhiyun 			if (rot < 0 || rot > 3) {
371*4882a593Smuzhiyun 				r = -EINVAL;
372*4882a593Smuzhiyun 				goto out;
373*4882a593Smuzhiyun 			}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 			if (ofbi->rotation[num_ovls] != rot)
376*4882a593Smuzhiyun 				changed = true;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 			rotation[num_ovls++] = rot;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 			p++;
381*4882a593Smuzhiyun 		}
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (num_ovls != ofbi->num_overlays) {
385*4882a593Smuzhiyun 		r = -EINVAL;
386*4882a593Smuzhiyun 		goto out;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	if (changed) {
390*4882a593Smuzhiyun 		for (i = 0; i < num_ovls; ++i)
391*4882a593Smuzhiyun 			ofbi->rotation[i] = rotation[i];
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 		omapfb_get_mem_region(ofbi->region);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 		r = omapfb_apply_changes(fbi, 0);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 		omapfb_put_mem_region(ofbi->region);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 		if (r)
400*4882a593Smuzhiyun 			goto out;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 		/* FIXME error handling? */
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	r = count;
406*4882a593Smuzhiyun out:
407*4882a593Smuzhiyun 	unlock_fb_info(fbi);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	return r;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
show_size(struct device * dev,struct device_attribute * attr,char * buf)412*4882a593Smuzhiyun static ssize_t show_size(struct device *dev,
413*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
416*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
store_size(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)421*4882a593Smuzhiyun static ssize_t store_size(struct device *dev, struct device_attribute *attr,
422*4882a593Smuzhiyun 		const char *buf, size_t count)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
425*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
426*4882a593Smuzhiyun 	struct omapfb2_device *fbdev = ofbi->fbdev;
427*4882a593Smuzhiyun 	struct omap_dss_device *display = fb2display(fbi);
428*4882a593Smuzhiyun 	struct omapfb2_mem_region *rg;
429*4882a593Smuzhiyun 	unsigned long size;
430*4882a593Smuzhiyun 	int r;
431*4882a593Smuzhiyun 	int i;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	r = kstrtoul(buf, 0, &size);
434*4882a593Smuzhiyun 	if (r)
435*4882a593Smuzhiyun 		return r;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	size = PAGE_ALIGN(size);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	lock_fb_info(fbi);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	if (display && display->driver->sync)
442*4882a593Smuzhiyun 		display->driver->sync(display);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	rg = ofbi->region;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	down_write_nested(&rg->lock, rg->id);
447*4882a593Smuzhiyun 	atomic_inc(&rg->lock_count);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	if (atomic_read(&rg->map_count)) {
450*4882a593Smuzhiyun 		r = -EBUSY;
451*4882a593Smuzhiyun 		goto out;
452*4882a593Smuzhiyun 	}
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	for (i = 0; i < fbdev->num_fbs; i++) {
455*4882a593Smuzhiyun 		struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
456*4882a593Smuzhiyun 		int j;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 		if (ofbi2->region != rg)
459*4882a593Smuzhiyun 			continue;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 		for (j = 0; j < ofbi2->num_overlays; j++) {
462*4882a593Smuzhiyun 			struct omap_overlay *ovl;
463*4882a593Smuzhiyun 			ovl = ofbi2->overlays[j];
464*4882a593Smuzhiyun 			if (ovl->is_enabled(ovl)) {
465*4882a593Smuzhiyun 				r = -EBUSY;
466*4882a593Smuzhiyun 				goto out;
467*4882a593Smuzhiyun 			}
468*4882a593Smuzhiyun 		}
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	if (size != ofbi->region->size) {
472*4882a593Smuzhiyun 		r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
473*4882a593Smuzhiyun 		if (r) {
474*4882a593Smuzhiyun 			dev_err(dev, "realloc fbmem failed\n");
475*4882a593Smuzhiyun 			goto out;
476*4882a593Smuzhiyun 		}
477*4882a593Smuzhiyun 	}
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	r = count;
480*4882a593Smuzhiyun out:
481*4882a593Smuzhiyun 	atomic_dec(&rg->lock_count);
482*4882a593Smuzhiyun 	up_write(&rg->lock);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	unlock_fb_info(fbi);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	return r;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun 
show_phys(struct device * dev,struct device_attribute * attr,char * buf)489*4882a593Smuzhiyun static ssize_t show_phys(struct device *dev,
490*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
493*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
show_virt(struct device * dev,struct device_attribute * attr,char * buf)498*4882a593Smuzhiyun static ssize_t show_virt(struct device *dev,
499*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
502*4882a593Smuzhiyun 	struct omapfb_info *ofbi = FB2OFB(fbi);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun 
show_upd_mode(struct device * dev,struct device_attribute * attr,char * buf)507*4882a593Smuzhiyun static ssize_t show_upd_mode(struct device *dev,
508*4882a593Smuzhiyun 		struct device_attribute *attr, char *buf)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
511*4882a593Smuzhiyun 	enum omapfb_update_mode mode;
512*4882a593Smuzhiyun 	int r;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	r = omapfb_get_update_mode(fbi, &mode);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	if (r)
517*4882a593Smuzhiyun 		return r;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun 
store_upd_mode(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)522*4882a593Smuzhiyun static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
523*4882a593Smuzhiyun 		const char *buf, size_t count)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun 	struct fb_info *fbi = dev_get_drvdata(dev);
526*4882a593Smuzhiyun 	unsigned mode;
527*4882a593Smuzhiyun 	int r;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	r = kstrtouint(buf, 0, &mode);
530*4882a593Smuzhiyun 	if (r)
531*4882a593Smuzhiyun 		return r;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	r = omapfb_set_update_mode(fbi, mode);
534*4882a593Smuzhiyun 	if (r)
535*4882a593Smuzhiyun 		return r;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	return count;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun static struct device_attribute omapfb_attrs[] = {
541*4882a593Smuzhiyun 	__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
542*4882a593Smuzhiyun 			store_rotate_type),
543*4882a593Smuzhiyun 	__ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
544*4882a593Smuzhiyun 	__ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
545*4882a593Smuzhiyun 	__ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
546*4882a593Smuzhiyun 	__ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
547*4882a593Smuzhiyun 			store_overlays_rotate),
548*4882a593Smuzhiyun 	__ATTR(phys_addr, S_IRUGO, show_phys, NULL),
549*4882a593Smuzhiyun 	__ATTR(virt_addr, S_IRUGO, show_virt, NULL),
550*4882a593Smuzhiyun 	__ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
551*4882a593Smuzhiyun };
552*4882a593Smuzhiyun 
omapfb_create_sysfs(struct omapfb2_device * fbdev)553*4882a593Smuzhiyun int omapfb_create_sysfs(struct omapfb2_device *fbdev)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun 	int i;
556*4882a593Smuzhiyun 	int r;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	DBG("create sysfs for fbs\n");
559*4882a593Smuzhiyun 	for (i = 0; i < fbdev->num_fbs; i++) {
560*4882a593Smuzhiyun 		int t;
561*4882a593Smuzhiyun 		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
562*4882a593Smuzhiyun 			r = device_create_file(fbdev->fbs[i]->dev,
563*4882a593Smuzhiyun 					&omapfb_attrs[t]);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 			if (r) {
566*4882a593Smuzhiyun 				dev_err(fbdev->dev, "failed to create sysfs "
567*4882a593Smuzhiyun 						"file\n");
568*4882a593Smuzhiyun 				return r;
569*4882a593Smuzhiyun 			}
570*4882a593Smuzhiyun 		}
571*4882a593Smuzhiyun 	}
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	return 0;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
omapfb_remove_sysfs(struct omapfb2_device * fbdev)576*4882a593Smuzhiyun void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun 	int i, t;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	DBG("remove sysfs for fbs\n");
581*4882a593Smuzhiyun 	for (i = 0; i < fbdev->num_fbs; i++) {
582*4882a593Smuzhiyun 		for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
583*4882a593Smuzhiyun 			device_remove_file(fbdev->fbs[i]->dev,
584*4882a593Smuzhiyun 					&omapfb_attrs[t]);
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
588