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