517 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2009 Nokia Corporation4 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>5 *6 * Some code and ideas taken from drivers/video/omap/ driver7 * by Imre Deak.8 */9 10#define DSS_SUBSYS_NAME "MANAGER"11 12#include <linux/kernel.h>13#include <linux/kstrtox.h>14#include <linux/slab.h>15#include <linux/module.h>16#include <linux/platform_device.h>17#include <linux/jiffies.h>18 19#include <video/omapfb_dss.h>20 21#include "dss.h"22#include "dss_features.h"23 24static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)25{26 return sysfs_emit(buf, "%s\n", mgr->name);27}28 29static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)30{31 struct omap_dss_device *dssdev = mgr->get_device(mgr);32 33 return sysfs_emit(buf, "%s\n", dssdev ?34 dssdev->name : "<none>");35}36 37static int manager_display_match(struct omap_dss_device *dssdev, void *data)38{39 const char *str = data;40 41 return sysfs_streq(dssdev->name, str);42}43 44static ssize_t manager_display_store(struct omap_overlay_manager *mgr,45 const char *buf, size_t size)46{47 int r = 0;48 size_t len = size;49 struct omap_dss_device *dssdev = NULL;50 struct omap_dss_device *old_dssdev;51 52 if (buf[size-1] == '\n')53 --len;54 55 if (len > 0)56 dssdev = omap_dss_find_device((void *)buf,57 manager_display_match);58 59 if (len > 0 && dssdev == NULL)60 return -EINVAL;61 62 if (dssdev) {63 DSSDBG("display %s found\n", dssdev->name);64 65 if (omapdss_device_is_connected(dssdev)) {66 DSSERR("new display is already connected\n");67 r = -EINVAL;68 goto put_device;69 }70 71 if (omapdss_device_is_enabled(dssdev)) {72 DSSERR("new display is not disabled\n");73 r = -EINVAL;74 goto put_device;75 }76 }77 78 old_dssdev = mgr->get_device(mgr);79 if (old_dssdev) {80 if (omapdss_device_is_enabled(old_dssdev)) {81 DSSERR("old display is not disabled\n");82 r = -EINVAL;83 goto put_device;84 }85 86 old_dssdev->driver->disconnect(old_dssdev);87 }88 89 if (dssdev) {90 r = dssdev->driver->connect(dssdev);91 if (r) {92 DSSERR("failed to connect new device\n");93 goto put_device;94 }95 96 old_dssdev = mgr->get_device(mgr);97 if (old_dssdev != dssdev) {98 DSSERR("failed to connect device to this manager\n");99 dssdev->driver->disconnect(dssdev);100 goto put_device;101 }102 103 r = mgr->apply(mgr);104 if (r) {105 DSSERR("failed to apply dispc config\n");106 goto put_device;107 }108 }109 110put_device:111 if (dssdev)112 omap_dss_put_device(dssdev);113 114 return r ? r : size;115}116 117static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,118 char *buf)119{120 struct omap_overlay_manager_info info;121 122 mgr->get_manager_info(mgr, &info);123 124 return sysfs_emit(buf, "%#x\n", info.default_color);125}126 127static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,128 const char *buf, size_t size)129{130 struct omap_overlay_manager_info info;131 u32 color;132 int r;133 134 r = kstrtouint(buf, 0, &color);135 if (r)136 return r;137 138 mgr->get_manager_info(mgr, &info);139 140 info.default_color = color;141 142 r = mgr->set_manager_info(mgr, &info);143 if (r)144 return r;145 146 r = mgr->apply(mgr);147 if (r)148 return r;149 150 return size;151}152 153static const char *trans_key_type_str[] = {154 "gfx-destination",155 "video-source",156};157 158static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,159 char *buf)160{161 enum omap_dss_trans_key_type key_type;162 struct omap_overlay_manager_info info;163 164 mgr->get_manager_info(mgr, &info);165 166 key_type = info.trans_key_type;167 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));168 169 return sysfs_emit(buf, "%s\n", trans_key_type_str[key_type]);170}171 172static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,173 const char *buf, size_t size)174{175 struct omap_overlay_manager_info info;176 int r;177 178 r = sysfs_match_string(trans_key_type_str, buf);179 if (r < 0)180 return r;181 182 mgr->get_manager_info(mgr, &info);183 184 info.trans_key_type = r;185 186 r = mgr->set_manager_info(mgr, &info);187 if (r)188 return r;189 190 r = mgr->apply(mgr);191 if (r)192 return r;193 194 return size;195}196 197static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,198 char *buf)199{200 struct omap_overlay_manager_info info;201 202 mgr->get_manager_info(mgr, &info);203 204 return sysfs_emit(buf, "%#x\n", info.trans_key);205}206 207static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,208 const char *buf, size_t size)209{210 struct omap_overlay_manager_info info;211 u32 key_value;212 int r;213 214 r = kstrtouint(buf, 0, &key_value);215 if (r)216 return r;217 218 mgr->get_manager_info(mgr, &info);219 220 info.trans_key = key_value;221 222 r = mgr->set_manager_info(mgr, &info);223 if (r)224 return r;225 226 r = mgr->apply(mgr);227 if (r)228 return r;229 230 return size;231}232 233static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,234 char *buf)235{236 struct omap_overlay_manager_info info;237 238 mgr->get_manager_info(mgr, &info);239 240 return sysfs_emit(buf, "%d\n", info.trans_enabled);241}242 243static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,244 const char *buf, size_t size)245{246 struct omap_overlay_manager_info info;247 bool enable;248 int r;249 250 r = kstrtobool(buf, &enable);251 if (r)252 return r;253 254 mgr->get_manager_info(mgr, &info);255 256 info.trans_enabled = enable;257 258 r = mgr->set_manager_info(mgr, &info);259 if (r)260 return r;261 262 r = mgr->apply(mgr);263 if (r)264 return r;265 266 return size;267}268 269static ssize_t manager_alpha_blending_enabled_show(270 struct omap_overlay_manager *mgr, char *buf)271{272 struct omap_overlay_manager_info info;273 274 if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))275 return -ENODEV;276 277 mgr->get_manager_info(mgr, &info);278 279 return sysfs_emit(buf, "%d\n",280 info.partial_alpha_enabled);281}282 283static ssize_t manager_alpha_blending_enabled_store(284 struct omap_overlay_manager *mgr,285 const char *buf, size_t size)286{287 struct omap_overlay_manager_info info;288 bool enable;289 int r;290 291 if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))292 return -ENODEV;293 294 r = kstrtobool(buf, &enable);295 if (r)296 return r;297 298 mgr->get_manager_info(mgr, &info);299 300 info.partial_alpha_enabled = enable;301 302 r = mgr->set_manager_info(mgr, &info);303 if (r)304 return r;305 306 r = mgr->apply(mgr);307 if (r)308 return r;309 310 return size;311}312 313static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,314 char *buf)315{316 struct omap_overlay_manager_info info;317 318 mgr->get_manager_info(mgr, &info);319 320 return sysfs_emit(buf, "%d\n", info.cpr_enable);321}322 323static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,324 const char *buf, size_t size)325{326 struct omap_overlay_manager_info info;327 int r;328 bool enable;329 330 if (!dss_has_feature(FEAT_CPR))331 return -ENODEV;332 333 r = kstrtobool(buf, &enable);334 if (r)335 return r;336 337 mgr->get_manager_info(mgr, &info);338 339 if (info.cpr_enable == enable)340 return size;341 342 info.cpr_enable = enable;343 344 r = mgr->set_manager_info(mgr, &info);345 if (r)346 return r;347 348 r = mgr->apply(mgr);349 if (r)350 return r;351 352 return size;353}354 355static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,356 char *buf)357{358 struct omap_overlay_manager_info info;359 360 mgr->get_manager_info(mgr, &info);361 362 return sysfs_emit(buf,363 "%d %d %d %d %d %d %d %d %d\n",364 info.cpr_coefs.rr,365 info.cpr_coefs.rg,366 info.cpr_coefs.rb,367 info.cpr_coefs.gr,368 info.cpr_coefs.gg,369 info.cpr_coefs.gb,370 info.cpr_coefs.br,371 info.cpr_coefs.bg,372 info.cpr_coefs.bb);373}374 375static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,376 const char *buf, size_t size)377{378 struct omap_overlay_manager_info info;379 struct omap_dss_cpr_coefs coefs;380 int r, i;381 s16 *arr;382 383 if (!dss_has_feature(FEAT_CPR))384 return -ENODEV;385 386 if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",387 &coefs.rr, &coefs.rg, &coefs.rb,388 &coefs.gr, &coefs.gg, &coefs.gb,389 &coefs.br, &coefs.bg, &coefs.bb) != 9)390 return -EINVAL;391 392 arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,393 coefs.gr, coefs.gg, coefs.gb,394 coefs.br, coefs.bg, coefs.bb };395 396 for (i = 0; i < 9; ++i) {397 if (arr[i] < -512 || arr[i] > 511)398 return -EINVAL;399 }400 401 mgr->get_manager_info(mgr, &info);402 403 info.cpr_coefs = coefs;404 405 r = mgr->set_manager_info(mgr, &info);406 if (r)407 return r;408 409 r = mgr->apply(mgr);410 if (r)411 return r;412 413 return size;414}415 416struct manager_attribute {417 struct attribute attr;418 ssize_t (*show)(struct omap_overlay_manager *, char *);419 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);420};421 422#define MANAGER_ATTR(_name, _mode, _show, _store) \423 struct manager_attribute manager_attr_##_name = \424 __ATTR(_name, _mode, _show, _store)425 426static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);427static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,428 manager_display_show, manager_display_store);429static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,430 manager_default_color_show, manager_default_color_store);431static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,432 manager_trans_key_type_show, manager_trans_key_type_store);433static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,434 manager_trans_key_value_show, manager_trans_key_value_store);435static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,436 manager_trans_key_enabled_show,437 manager_trans_key_enabled_store);438static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,439 manager_alpha_blending_enabled_show,440 manager_alpha_blending_enabled_store);441static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,442 manager_cpr_enable_show,443 manager_cpr_enable_store);444static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,445 manager_cpr_coef_show,446 manager_cpr_coef_store);447 448 449static struct attribute *manager_sysfs_attrs[] = {450 &manager_attr_name.attr,451 &manager_attr_display.attr,452 &manager_attr_default_color.attr,453 &manager_attr_trans_key_type.attr,454 &manager_attr_trans_key_value.attr,455 &manager_attr_trans_key_enabled.attr,456 &manager_attr_alpha_blending_enabled.attr,457 &manager_attr_cpr_enable.attr,458 &manager_attr_cpr_coef.attr,459 NULL460};461ATTRIBUTE_GROUPS(manager_sysfs);462 463static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,464 char *buf)465{466 struct omap_overlay_manager *manager;467 struct manager_attribute *manager_attr;468 469 manager = container_of(kobj, struct omap_overlay_manager, kobj);470 manager_attr = container_of(attr, struct manager_attribute, attr);471 472 if (!manager_attr->show)473 return -ENOENT;474 475 return manager_attr->show(manager, buf);476}477 478static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,479 const char *buf, size_t size)480{481 struct omap_overlay_manager *manager;482 struct manager_attribute *manager_attr;483 484 manager = container_of(kobj, struct omap_overlay_manager, kobj);485 manager_attr = container_of(attr, struct manager_attribute, attr);486 487 if (!manager_attr->store)488 return -ENOENT;489 490 return manager_attr->store(manager, buf, size);491}492 493static const struct sysfs_ops manager_sysfs_ops = {494 .show = manager_attr_show,495 .store = manager_attr_store,496};497 498static struct kobj_type manager_ktype = {499 .sysfs_ops = &manager_sysfs_ops,500 .default_groups = manager_sysfs_groups,501};502 503int dss_manager_kobj_init(struct omap_overlay_manager *mgr,504 struct platform_device *pdev)505{506 return kobject_init_and_add(&mgr->kobj, &manager_ktype,507 &pdev->dev.kobj, "manager%d", mgr->id);508}509 510void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)511{512 kobject_del(&mgr->kobj);513 kobject_put(&mgr->kobj);514 515 memset(&mgr->kobj, 0, sizeof(mgr->kobj));516}517