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