1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2009 Nokia Corporation
4 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
5 *
6 * Some code and ideas taken from drivers/video/omap/ driver
7 * by Imre Deak.
8 */
9
10 #define DSS_SUBSYS_NAME "OVERLAY"
11
12 #include <linux/module.h>
13 #include <linux/err.h>
14 #include <linux/sysfs.h>
15 #include <linux/kobject.h>
16 #include <linux/platform_device.h>
17
18 #include <video/omapfb_dss.h>
19
20 #include "dss.h"
21 #include "dss_features.h"
22
overlay_name_show(struct omap_overlay * ovl,char * buf)23 static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
24 {
25 return sysfs_emit(buf, "%s\n", ovl->name);
26 }
27
overlay_manager_show(struct omap_overlay * ovl,char * buf)28 static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
29 {
30 return sysfs_emit(buf, "%s\n",
31 ovl->manager ? ovl->manager->name : "<none>");
32 }
33
overlay_manager_store(struct omap_overlay * ovl,const char * buf,size_t size)34 static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
35 size_t size)
36 {
37 int i, r;
38 struct omap_overlay_manager *mgr = NULL;
39 struct omap_overlay_manager *old_mgr;
40 int len = size;
41
42 if (buf[size-1] == '\n')
43 --len;
44
45 if (len > 0) {
46 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
47 mgr = omap_dss_get_overlay_manager(i);
48
49 if (sysfs_streq(buf, mgr->name))
50 break;
51
52 mgr = NULL;
53 }
54 }
55
56 if (len > 0 && mgr == NULL)
57 return -EINVAL;
58
59 if (mgr)
60 DSSDBG("manager %s found\n", mgr->name);
61
62 if (mgr == ovl->manager)
63 return size;
64
65 old_mgr = ovl->manager;
66
67 r = dispc_runtime_get();
68 if (r)
69 return r;
70
71 /* detach old manager */
72 if (old_mgr) {
73 r = ovl->unset_manager(ovl);
74 if (r) {
75 DSSERR("detach failed\n");
76 goto err;
77 }
78
79 r = old_mgr->apply(old_mgr);
80 if (r)
81 goto err;
82 }
83
84 if (mgr) {
85 r = ovl->set_manager(ovl, mgr);
86 if (r) {
87 DSSERR("Failed to attach overlay\n");
88 goto err;
89 }
90
91 r = mgr->apply(mgr);
92 if (r)
93 goto err;
94 }
95
96 dispc_runtime_put();
97
98 return size;
99
100 err:
101 dispc_runtime_put();
102 return r;
103 }
104
overlay_input_size_show(struct omap_overlay * ovl,char * buf)105 static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
106 {
107 struct omap_overlay_info info;
108
109 ovl->get_overlay_info(ovl, &info);
110
111 return sysfs_emit(buf, "%d,%d\n",
112 info.width, info.height);
113 }
114
overlay_screen_width_show(struct omap_overlay * ovl,char * buf)115 static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
116 {
117 struct omap_overlay_info info;
118
119 ovl->get_overlay_info(ovl, &info);
120
121 return sysfs_emit(buf, "%d\n", info.screen_width);
122 }
123
overlay_position_show(struct omap_overlay * ovl,char * buf)124 static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
125 {
126 struct omap_overlay_info info;
127
128 ovl->get_overlay_info(ovl, &info);
129
130 return sysfs_emit(buf, "%d,%d\n",
131 info.pos_x, info.pos_y);
132 }
133
overlay_position_store(struct omap_overlay * ovl,const char * buf,size_t size)134 static ssize_t overlay_position_store(struct omap_overlay *ovl,
135 const char *buf, size_t size)
136 {
137 int r;
138 char *last;
139 struct omap_overlay_info info;
140
141 ovl->get_overlay_info(ovl, &info);
142
143 info.pos_x = simple_strtoul(buf, &last, 10);
144 ++last;
145 if (last - buf >= size)
146 return -EINVAL;
147
148 info.pos_y = simple_strtoul(last, &last, 10);
149
150 r = ovl->set_overlay_info(ovl, &info);
151 if (r)
152 return r;
153
154 if (ovl->manager) {
155 r = ovl->manager->apply(ovl->manager);
156 if (r)
157 return r;
158 }
159
160 return size;
161 }
162
overlay_output_size_show(struct omap_overlay * ovl,char * buf)163 static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
164 {
165 struct omap_overlay_info info;
166
167 ovl->get_overlay_info(ovl, &info);
168
169 return sysfs_emit(buf, "%d,%d\n",
170 info.out_width, info.out_height);
171 }
172
overlay_output_size_store(struct omap_overlay * ovl,const char * buf,size_t size)173 static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
174 const char *buf, size_t size)
175 {
176 int r;
177 char *last;
178 struct omap_overlay_info info;
179
180 ovl->get_overlay_info(ovl, &info);
181
182 info.out_width = simple_strtoul(buf, &last, 10);
183 ++last;
184 if (last - buf >= size)
185 return -EINVAL;
186
187 info.out_height = simple_strtoul(last, &last, 10);
188
189 r = ovl->set_overlay_info(ovl, &info);
190 if (r)
191 return r;
192
193 if (ovl->manager) {
194 r = ovl->manager->apply(ovl->manager);
195 if (r)
196 return r;
197 }
198
199 return size;
200 }
201
overlay_enabled_show(struct omap_overlay * ovl,char * buf)202 static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
203 {
204 return sysfs_emit(buf, "%d\n", ovl->is_enabled(ovl));
205 }
206
overlay_enabled_store(struct omap_overlay * ovl,const char * buf,size_t size)207 static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
208 size_t size)
209 {
210 int r;
211 bool enable;
212
213 r = strtobool(buf, &enable);
214 if (r)
215 return r;
216
217 if (enable)
218 r = ovl->enable(ovl);
219 else
220 r = ovl->disable(ovl);
221
222 if (r)
223 return r;
224
225 return size;
226 }
227
overlay_global_alpha_show(struct omap_overlay * ovl,char * buf)228 static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
229 {
230 struct omap_overlay_info info;
231
232 ovl->get_overlay_info(ovl, &info);
233
234 return sysfs_emit(buf, "%d\n",
235 info.global_alpha);
236 }
237
overlay_global_alpha_store(struct omap_overlay * ovl,const char * buf,size_t size)238 static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
239 const char *buf, size_t size)
240 {
241 int r;
242 u8 alpha;
243 struct omap_overlay_info info;
244
245 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
246 return -ENODEV;
247
248 r = kstrtou8(buf, 0, &alpha);
249 if (r)
250 return r;
251
252 ovl->get_overlay_info(ovl, &info);
253
254 info.global_alpha = alpha;
255
256 r = ovl->set_overlay_info(ovl, &info);
257 if (r)
258 return r;
259
260 if (ovl->manager) {
261 r = ovl->manager->apply(ovl->manager);
262 if (r)
263 return r;
264 }
265
266 return size;
267 }
268
overlay_pre_mult_alpha_show(struct omap_overlay * ovl,char * buf)269 static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
270 char *buf)
271 {
272 struct omap_overlay_info info;
273
274 ovl->get_overlay_info(ovl, &info);
275
276 return sysfs_emit(buf, "%d\n",
277 info.pre_mult_alpha);
278 }
279
overlay_pre_mult_alpha_store(struct omap_overlay * ovl,const char * buf,size_t size)280 static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
281 const char *buf, size_t size)
282 {
283 int r;
284 u8 alpha;
285 struct omap_overlay_info info;
286
287 if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
288 return -ENODEV;
289
290 r = kstrtou8(buf, 0, &alpha);
291 if (r)
292 return r;
293
294 ovl->get_overlay_info(ovl, &info);
295
296 info.pre_mult_alpha = alpha;
297
298 r = ovl->set_overlay_info(ovl, &info);
299 if (r)
300 return r;
301
302 if (ovl->manager) {
303 r = ovl->manager->apply(ovl->manager);
304 if (r)
305 return r;
306 }
307
308 return size;
309 }
310
overlay_zorder_show(struct omap_overlay * ovl,char * buf)311 static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
312 {
313 struct omap_overlay_info info;
314
315 ovl->get_overlay_info(ovl, &info);
316
317 return sysfs_emit(buf, "%d\n", info.zorder);
318 }
319
overlay_zorder_store(struct omap_overlay * ovl,const char * buf,size_t size)320 static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
321 const char *buf, size_t size)
322 {
323 int r;
324 u8 zorder;
325 struct omap_overlay_info info;
326
327 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
328 return -ENODEV;
329
330 r = kstrtou8(buf, 0, &zorder);
331 if (r)
332 return r;
333
334 ovl->get_overlay_info(ovl, &info);
335
336 info.zorder = zorder;
337
338 r = ovl->set_overlay_info(ovl, &info);
339 if (r)
340 return r;
341
342 if (ovl->manager) {
343 r = ovl->manager->apply(ovl->manager);
344 if (r)
345 return r;
346 }
347
348 return size;
349 }
350
351 struct overlay_attribute {
352 struct attribute attr;
353 ssize_t (*show)(struct omap_overlay *, char *);
354 ssize_t (*store)(struct omap_overlay *, const char *, size_t);
355 };
356
357 #define OVERLAY_ATTR(_name, _mode, _show, _store) \
358 struct overlay_attribute overlay_attr_##_name = \
359 __ATTR(_name, _mode, _show, _store)
360
361 static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
362 static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
363 overlay_manager_show, overlay_manager_store);
364 static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
365 static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
366 static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
367 overlay_position_show, overlay_position_store);
368 static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
369 overlay_output_size_show, overlay_output_size_store);
370 static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
371 overlay_enabled_show, overlay_enabled_store);
372 static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
373 overlay_global_alpha_show, overlay_global_alpha_store);
374 static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
375 overlay_pre_mult_alpha_show,
376 overlay_pre_mult_alpha_store);
377 static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
378 overlay_zorder_show, overlay_zorder_store);
379
380 static struct attribute *overlay_sysfs_attrs[] = {
381 &overlay_attr_name.attr,
382 &overlay_attr_manager.attr,
383 &overlay_attr_input_size.attr,
384 &overlay_attr_screen_width.attr,
385 &overlay_attr_position.attr,
386 &overlay_attr_output_size.attr,
387 &overlay_attr_enabled.attr,
388 &overlay_attr_global_alpha.attr,
389 &overlay_attr_pre_mult_alpha.attr,
390 &overlay_attr_zorder.attr,
391 NULL
392 };
393 ATTRIBUTE_GROUPS(overlay_sysfs);
394
overlay_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)395 static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
396 char *buf)
397 {
398 struct omap_overlay *overlay;
399 struct overlay_attribute *overlay_attr;
400
401 overlay = container_of(kobj, struct omap_overlay, kobj);
402 overlay_attr = container_of(attr, struct overlay_attribute, attr);
403
404 if (!overlay_attr->show)
405 return -ENOENT;
406
407 return overlay_attr->show(overlay, buf);
408 }
409
overlay_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t size)410 static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
411 const char *buf, size_t size)
412 {
413 struct omap_overlay *overlay;
414 struct overlay_attribute *overlay_attr;
415
416 overlay = container_of(kobj, struct omap_overlay, kobj);
417 overlay_attr = container_of(attr, struct overlay_attribute, attr);
418
419 if (!overlay_attr->store)
420 return -ENOENT;
421
422 return overlay_attr->store(overlay, buf, size);
423 }
424
425 static const struct sysfs_ops overlay_sysfs_ops = {
426 .show = overlay_attr_show,
427 .store = overlay_attr_store,
428 };
429
430 static struct kobj_type overlay_ktype = {
431 .sysfs_ops = &overlay_sysfs_ops,
432 .default_groups = overlay_sysfs_groups,
433 };
434
dss_overlay_kobj_init(struct omap_overlay * ovl,struct platform_device * pdev)435 int dss_overlay_kobj_init(struct omap_overlay *ovl,
436 struct platform_device *pdev)
437 {
438 return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
439 &pdev->dev.kobj, "overlay%d", ovl->id);
440 }
441
dss_overlay_kobj_uninit(struct omap_overlay * ovl)442 void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
443 {
444 kobject_del(&ovl->kobj);
445 kobject_put(&ovl->kobj);
446 }
447