overlay.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. /*
  2. * linux/drivers/video/omap2/dss/overlay.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 "OVERLAY"
  23. #include <linux/kernel.h>
  24. #include <linux/module.h>
  25. #include <linux/err.h>
  26. #include <linux/sysfs.h>
  27. #include <linux/kobject.h>
  28. #include <linux/platform_device.h>
  29. #include <linux/delay.h>
  30. #include <linux/slab.h>
  31. #include <plat/display.h>
  32. #include <plat/cpu.h>
  33. #include "dss.h"
  34. static int num_overlays;
  35. static struct list_head overlay_list;
  36. static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
  37. {
  38. return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
  39. }
  40. static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
  41. {
  42. return snprintf(buf, PAGE_SIZE, "%s\n",
  43. ovl->manager ? ovl->manager->name : "<none>");
  44. }
  45. static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
  46. size_t size)
  47. {
  48. int i, r;
  49. struct omap_overlay_manager *mgr = NULL;
  50. struct omap_overlay_manager *old_mgr;
  51. int len = size;
  52. if (buf[size-1] == '\n')
  53. --len;
  54. if (len > 0) {
  55. for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
  56. mgr = omap_dss_get_overlay_manager(i);
  57. if (strncmp(buf, mgr->name, len) == 0)
  58. break;
  59. mgr = NULL;
  60. }
  61. }
  62. if (len > 0 && mgr == NULL)
  63. return -EINVAL;
  64. if (mgr)
  65. DSSDBG("manager %s found\n", mgr->name);
  66. if (mgr == ovl->manager)
  67. return size;
  68. old_mgr = ovl->manager;
  69. /* detach old manager */
  70. if (old_mgr) {
  71. r = ovl->unset_manager(ovl);
  72. if (r) {
  73. DSSERR("detach failed\n");
  74. return r;
  75. }
  76. r = old_mgr->apply(old_mgr);
  77. if (r)
  78. return r;
  79. }
  80. if (mgr) {
  81. r = ovl->set_manager(ovl, mgr);
  82. if (r) {
  83. DSSERR("Failed to attach overlay\n");
  84. return r;
  85. }
  86. r = mgr->apply(mgr);
  87. if (r)
  88. return r;
  89. }
  90. return size;
  91. }
  92. static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
  93. {
  94. return snprintf(buf, PAGE_SIZE, "%d,%d\n",
  95. ovl->info.width, ovl->info.height);
  96. }
  97. static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
  98. {
  99. return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
  100. }
  101. static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
  102. {
  103. return snprintf(buf, PAGE_SIZE, "%d,%d\n",
  104. ovl->info.pos_x, ovl->info.pos_y);
  105. }
  106. static ssize_t overlay_position_store(struct omap_overlay *ovl,
  107. const char *buf, size_t size)
  108. {
  109. int r;
  110. char *last;
  111. struct omap_overlay_info info;
  112. ovl->get_overlay_info(ovl, &info);
  113. info.pos_x = simple_strtoul(buf, &last, 10);
  114. ++last;
  115. if (last - buf >= size)
  116. return -EINVAL;
  117. info.pos_y = simple_strtoul(last, &last, 10);
  118. r = ovl->set_overlay_info(ovl, &info);
  119. if (r)
  120. return r;
  121. if (ovl->manager) {
  122. r = ovl->manager->apply(ovl->manager);
  123. if (r)
  124. return r;
  125. }
  126. return size;
  127. }
  128. static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
  129. {
  130. return snprintf(buf, PAGE_SIZE, "%d,%d\n",
  131. ovl->info.out_width, ovl->info.out_height);
  132. }
  133. static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
  134. const char *buf, size_t size)
  135. {
  136. int r;
  137. char *last;
  138. struct omap_overlay_info info;
  139. ovl->get_overlay_info(ovl, &info);
  140. info.out_width = simple_strtoul(buf, &last, 10);
  141. ++last;
  142. if (last - buf >= size)
  143. return -EINVAL;
  144. info.out_height = simple_strtoul(last, &last, 10);
  145. r = ovl->set_overlay_info(ovl, &info);
  146. if (r)
  147. return r;
  148. if (ovl->manager) {
  149. r = ovl->manager->apply(ovl->manager);
  150. if (r)
  151. return r;
  152. }
  153. return size;
  154. }
  155. static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
  156. {
  157. return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
  158. }
  159. static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
  160. size_t size)
  161. {
  162. int r;
  163. struct omap_overlay_info info;
  164. ovl->get_overlay_info(ovl, &info);
  165. info.enabled = simple_strtoul(buf, NULL, 10);
  166. r = ovl->set_overlay_info(ovl, &info);
  167. if (r)
  168. return r;
  169. if (ovl->manager) {
  170. r = ovl->manager->apply(ovl->manager);
  171. if (r)
  172. return r;
  173. }
  174. return size;
  175. }
  176. static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
  177. {
  178. return snprintf(buf, PAGE_SIZE, "%d\n",
  179. ovl->info.global_alpha);
  180. }
  181. static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
  182. const char *buf, size_t size)
  183. {
  184. int r;
  185. struct omap_overlay_info info;
  186. ovl->get_overlay_info(ovl, &info);
  187. /* Video1 plane does not support global alpha
  188. * to always make it 255 completely opaque
  189. */
  190. if (ovl->id == OMAP_DSS_VIDEO1)
  191. info.global_alpha = 255;
  192. else
  193. info.global_alpha = simple_strtoul(buf, NULL, 10);
  194. r = ovl->set_overlay_info(ovl, &info);
  195. if (r)
  196. return r;
  197. if (ovl->manager) {
  198. r = ovl->manager->apply(ovl->manager);
  199. if (r)
  200. return r;
  201. }
  202. return size;
  203. }
  204. struct overlay_attribute {
  205. struct attribute attr;
  206. ssize_t (*show)(struct omap_overlay *, char *);
  207. ssize_t (*store)(struct omap_overlay *, const char *, size_t);
  208. };
  209. #define OVERLAY_ATTR(_name, _mode, _show, _store) \
  210. struct overlay_attribute overlay_attr_##_name = \
  211. __ATTR(_name, _mode, _show, _store)
  212. static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
  213. static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
  214. overlay_manager_show, overlay_manager_store);
  215. static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
  216. static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
  217. static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
  218. overlay_position_show, overlay_position_store);
  219. static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
  220. overlay_output_size_show, overlay_output_size_store);
  221. static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
  222. overlay_enabled_show, overlay_enabled_store);
  223. static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
  224. overlay_global_alpha_show, overlay_global_alpha_store);
  225. static struct attribute *overlay_sysfs_attrs[] = {
  226. &overlay_attr_name.attr,
  227. &overlay_attr_manager.attr,
  228. &overlay_attr_input_size.attr,
  229. &overlay_attr_screen_width.attr,
  230. &overlay_attr_position.attr,
  231. &overlay_attr_output_size.attr,
  232. &overlay_attr_enabled.attr,
  233. &overlay_attr_global_alpha.attr,
  234. NULL
  235. };
  236. static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
  237. char *buf)
  238. {
  239. struct omap_overlay *overlay;
  240. struct overlay_attribute *overlay_attr;
  241. overlay = container_of(kobj, struct omap_overlay, kobj);
  242. overlay_attr = container_of(attr, struct overlay_attribute, attr);
  243. if (!overlay_attr->show)
  244. return -ENOENT;
  245. return overlay_attr->show(overlay, buf);
  246. }
  247. static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
  248. const char *buf, size_t size)
  249. {
  250. struct omap_overlay *overlay;
  251. struct overlay_attribute *overlay_attr;
  252. overlay = container_of(kobj, struct omap_overlay, kobj);
  253. overlay_attr = container_of(attr, struct overlay_attribute, attr);
  254. if (!overlay_attr->store)
  255. return -ENOENT;
  256. return overlay_attr->store(overlay, buf, size);
  257. }
  258. static const struct sysfs_ops overlay_sysfs_ops = {
  259. .show = overlay_attr_show,
  260. .store = overlay_attr_store,
  261. };
  262. static struct kobj_type overlay_ktype = {
  263. .sysfs_ops = &overlay_sysfs_ops,
  264. .default_attrs = overlay_sysfs_attrs,
  265. };
  266. /* Check if overlay parameters are compatible with display */
  267. int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
  268. {
  269. struct omap_overlay_info *info;
  270. u16 outw, outh;
  271. u16 dw, dh;
  272. if (!dssdev)
  273. return 0;
  274. if (!ovl->info.enabled)
  275. return 0;
  276. info = &ovl->info;
  277. if (info->paddr == 0) {
  278. DSSDBG("check_overlay failed: paddr 0\n");
  279. return -EINVAL;
  280. }
  281. dssdev->driver->get_resolution(dssdev, &dw, &dh);
  282. DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
  283. ovl->id,
  284. info->pos_x, info->pos_y,
  285. info->width, info->height,
  286. info->out_width, info->out_height,
  287. dw, dh);
  288. if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
  289. outw = info->width;
  290. outh = info->height;
  291. } else {
  292. if (info->out_width == 0)
  293. outw = info->width;
  294. else
  295. outw = info->out_width;
  296. if (info->out_height == 0)
  297. outh = info->height;
  298. else
  299. outh = info->out_height;
  300. }
  301. if (dw < info->pos_x + outw) {
  302. DSSDBG("check_overlay failed 1: %d < %d + %d\n",
  303. dw, info->pos_x, outw);
  304. return -EINVAL;
  305. }
  306. if (dh < info->pos_y + outh) {
  307. DSSDBG("check_overlay failed 2: %d < %d + %d\n",
  308. dh, info->pos_y, outh);
  309. return -EINVAL;
  310. }
  311. if ((ovl->supported_modes & info->color_mode) == 0) {
  312. DSSERR("overlay doesn't support mode %d\n", info->color_mode);
  313. return -EINVAL;
  314. }
  315. return 0;
  316. }
  317. static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
  318. struct omap_overlay_info *info)
  319. {
  320. int r;
  321. struct omap_overlay_info old_info;
  322. old_info = ovl->info;
  323. ovl->info = *info;
  324. if (ovl->manager) {
  325. r = dss_check_overlay(ovl, ovl->manager->device);
  326. if (r) {
  327. ovl->info = old_info;
  328. return r;
  329. }
  330. }
  331. ovl->info_dirty = true;
  332. return 0;
  333. }
  334. static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
  335. struct omap_overlay_info *info)
  336. {
  337. *info = ovl->info;
  338. }
  339. static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
  340. {
  341. return dss_mgr_wait_for_go_ovl(ovl);
  342. }
  343. static int omap_dss_set_manager(struct omap_overlay *ovl,
  344. struct omap_overlay_manager *mgr)
  345. {
  346. if (!mgr)
  347. return -EINVAL;
  348. if (ovl->manager) {
  349. DSSERR("overlay '%s' already has a manager '%s'\n",
  350. ovl->name, ovl->manager->name);
  351. return -EINVAL;
  352. }
  353. if (ovl->info.enabled) {
  354. DSSERR("overlay has to be disabled to change the manager\n");
  355. return -EINVAL;
  356. }
  357. ovl->manager = mgr;
  358. dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
  359. /* XXX: on manual update display, in auto update mode, a bug happens
  360. * here. When an overlay is first enabled on LCD, then it's disabled,
  361. * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
  362. * errors. Waiting before changing the channel_out fixes it. I'm
  363. * guessing that the overlay is still somehow being used for the LCD,
  364. * but I don't understand how or why. */
  365. msleep(40);
  366. dispc_set_channel_out(ovl->id, mgr->id);
  367. dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
  368. return 0;
  369. }
  370. static int omap_dss_unset_manager(struct omap_overlay *ovl)
  371. {
  372. int r;
  373. if (!ovl->manager) {
  374. DSSERR("failed to detach overlay: manager not set\n");
  375. return -EINVAL;
  376. }
  377. if (ovl->info.enabled) {
  378. DSSERR("overlay has to be disabled to unset the manager\n");
  379. return -EINVAL;
  380. }
  381. r = ovl->wait_for_go(ovl);
  382. if (r)
  383. return r;
  384. ovl->manager = NULL;
  385. return 0;
  386. }
  387. int omap_dss_get_num_overlays(void)
  388. {
  389. return num_overlays;
  390. }
  391. EXPORT_SYMBOL(omap_dss_get_num_overlays);
  392. struct omap_overlay *omap_dss_get_overlay(int num)
  393. {
  394. int i = 0;
  395. struct omap_overlay *ovl;
  396. list_for_each_entry(ovl, &overlay_list, list) {
  397. if (i++ == num)
  398. return ovl;
  399. }
  400. return NULL;
  401. }
  402. EXPORT_SYMBOL(omap_dss_get_overlay);
  403. static void omap_dss_add_overlay(struct omap_overlay *overlay)
  404. {
  405. ++num_overlays;
  406. list_add_tail(&overlay->list, &overlay_list);
  407. }
  408. static struct omap_overlay *dispc_overlays[3];
  409. void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
  410. {
  411. mgr->num_overlays = 3;
  412. mgr->overlays = dispc_overlays;
  413. }
  414. #ifdef L4_EXAMPLE
  415. static struct omap_overlay *l4_overlays[1];
  416. void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
  417. {
  418. mgr->num_overlays = 1;
  419. mgr->overlays = l4_overlays;
  420. }
  421. #endif
  422. void dss_init_overlays(struct platform_device *pdev)
  423. {
  424. int i, r;
  425. INIT_LIST_HEAD(&overlay_list);
  426. num_overlays = 0;
  427. for (i = 0; i < 3; ++i) {
  428. struct omap_overlay *ovl;
  429. ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
  430. BUG_ON(ovl == NULL);
  431. switch (i) {
  432. case 0:
  433. ovl->name = "gfx";
  434. ovl->id = OMAP_DSS_GFX;
  435. ovl->supported_modes = cpu_is_omap34xx() ?
  436. OMAP_DSS_COLOR_GFX_OMAP3 :
  437. OMAP_DSS_COLOR_GFX_OMAP2;
  438. ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
  439. ovl->info.global_alpha = 255;
  440. break;
  441. case 1:
  442. ovl->name = "vid1";
  443. ovl->id = OMAP_DSS_VIDEO1;
  444. ovl->supported_modes = cpu_is_omap34xx() ?
  445. OMAP_DSS_COLOR_VID1_OMAP3 :
  446. OMAP_DSS_COLOR_VID_OMAP2;
  447. ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
  448. OMAP_DSS_OVL_CAP_DISPC;
  449. ovl->info.global_alpha = 255;
  450. break;
  451. case 2:
  452. ovl->name = "vid2";
  453. ovl->id = OMAP_DSS_VIDEO2;
  454. ovl->supported_modes = cpu_is_omap34xx() ?
  455. OMAP_DSS_COLOR_VID2_OMAP3 :
  456. OMAP_DSS_COLOR_VID_OMAP2;
  457. ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
  458. OMAP_DSS_OVL_CAP_DISPC;
  459. ovl->info.global_alpha = 255;
  460. break;
  461. }
  462. ovl->set_manager = &omap_dss_set_manager;
  463. ovl->unset_manager = &omap_dss_unset_manager;
  464. ovl->set_overlay_info = &dss_ovl_set_overlay_info;
  465. ovl->get_overlay_info = &dss_ovl_get_overlay_info;
  466. ovl->wait_for_go = &dss_ovl_wait_for_go;
  467. omap_dss_add_overlay(ovl);
  468. r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
  469. &pdev->dev.kobj, "overlay%d", i);
  470. if (r) {
  471. DSSERR("failed to create sysfs file\n");
  472. continue;
  473. }
  474. dispc_overlays[i] = ovl;
  475. }
  476. #ifdef L4_EXAMPLE
  477. {
  478. struct omap_overlay *ovl;
  479. ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
  480. BUG_ON(ovl == NULL);
  481. ovl->name = "l4";
  482. ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
  483. ovl->set_manager = &omap_dss_set_manager;
  484. ovl->unset_manager = &omap_dss_unset_manager;
  485. ovl->set_overlay_info = &dss_ovl_set_overlay_info;
  486. ovl->get_overlay_info = &dss_ovl_get_overlay_info;
  487. omap_dss_add_overlay(ovl);
  488. r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
  489. &pdev->dev.kobj, "overlayl4");
  490. if (r)
  491. DSSERR("failed to create sysfs file\n");
  492. l4_overlays[0] = ovl;
  493. }
  494. #endif
  495. }
  496. /* connect overlays to the new device, if not already connected. if force
  497. * selected, connect always. */
  498. void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
  499. {
  500. int i;
  501. struct omap_overlay_manager *lcd_mgr;
  502. struct omap_overlay_manager *tv_mgr;
  503. struct omap_overlay_manager *mgr = NULL;
  504. lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
  505. tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
  506. if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
  507. if (!lcd_mgr->device || force) {
  508. if (lcd_mgr->device)
  509. lcd_mgr->unset_device(lcd_mgr);
  510. lcd_mgr->set_device(lcd_mgr, dssdev);
  511. mgr = lcd_mgr;
  512. }
  513. }
  514. if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
  515. if (!tv_mgr->device || force) {
  516. if (tv_mgr->device)
  517. tv_mgr->unset_device(tv_mgr);
  518. tv_mgr->set_device(tv_mgr, dssdev);
  519. mgr = tv_mgr;
  520. }
  521. }
  522. if (mgr) {
  523. for (i = 0; i < 3; i++) {
  524. struct omap_overlay *ovl;
  525. ovl = omap_dss_get_overlay(i);
  526. if (!ovl->manager || force) {
  527. if (ovl->manager)
  528. omap_dss_unset_manager(ovl);
  529. omap_dss_set_manager(ovl, mgr);
  530. }
  531. }
  532. }
  533. }
  534. void dss_uninit_overlays(struct platform_device *pdev)
  535. {
  536. struct omap_overlay *ovl;
  537. while (!list_empty(&overlay_list)) {
  538. ovl = list_first_entry(&overlay_list,
  539. struct omap_overlay, list);
  540. list_del(&ovl->list);
  541. kobject_del(&ovl->kobj);
  542. kobject_put(&ovl->kobj);
  543. kfree(ovl);
  544. }
  545. num_overlays = 0;
  546. }