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 "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 24 static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) 25 { 26 return sysfs_emit(buf, "%s\n", mgr->name); 27 } 28 29 static 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 37 static 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 44 static 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 110 put_device: 111 if (dssdev) 112 omap_dss_put_device(dssdev); 113 114 return r ? r : size; 115 } 116 117 static 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 127 static 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 153 static const char *trans_key_type_str[] = { 154 "gfx-destination", 155 "video-source", 156 }; 157 158 static 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 172 static 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 197 static 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 207 static 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 233 static 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 243 static 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 269 static 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 283 static 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 313 static 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 323 static 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 355 static 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 375 static 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 416 struct 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 426 static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); 427 static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, 428 manager_display_show, manager_display_store); 429 static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, 430 manager_default_color_show, manager_default_color_store); 431 static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, 432 manager_trans_key_type_show, manager_trans_key_type_store); 433 static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, 434 manager_trans_key_value_show, manager_trans_key_value_store); 435 static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, 436 manager_trans_key_enabled_show, 437 manager_trans_key_enabled_store); 438 static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, 439 manager_alpha_blending_enabled_show, 440 manager_alpha_blending_enabled_store); 441 static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, 442 manager_cpr_enable_show, 443 manager_cpr_enable_store); 444 static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, 445 manager_cpr_coef_show, 446 manager_cpr_coef_store); 447 448 449 static 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 NULL 460 }; 461 ATTRIBUTE_GROUPS(manager_sysfs); 462 463 static 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 478 static 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 493 static const struct sysfs_ops manager_sysfs_ops = { 494 .show = manager_attr_show, 495 .store = manager_attr_store, 496 }; 497 498 static struct kobj_type manager_ktype = { 499 .sysfs_ops = &manager_sysfs_ops, 500 .default_groups = manager_sysfs_groups, 501 }; 502 503 int 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 510 void 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