manager.c 15 KB

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