mdss_mdp_rotator.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #define pr_fmt(fmt) "%s: " fmt, __func__
  14. #include <linux/errno.h>
  15. #include <linux/list.h>
  16. #include <linux/mutex.h>
  17. #include <linux/types.h>
  18. #include <linux/sync.h>
  19. #include <linux/sw_sync.h>
  20. #include "mdss_mdp.h"
  21. #include "mdss_mdp_rotator.h"
  22. #include "mdss_fb.h"
  23. #include "mdss_debug.h"
  24. #define MAX_ROTATOR_SESSIONS 8
  25. static DEFINE_MUTEX(rotator_lock);
  26. static struct mdss_mdp_rotator_session rotator_session[MAX_ROTATOR_SESSIONS];
  27. static LIST_HEAD(rotator_queue);
  28. static int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot);
  29. static void mdss_mdp_rotator_commit_wq_handler(struct work_struct *work);
  30. static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot);
  31. static int mdss_mdp_rotator_queue_helper(struct mdss_mdp_rotator_session *rot);
  32. static struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_create(
  33. struct mdss_mdp_rotator_session *rot);
  34. static struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void)
  35. {
  36. struct mdss_mdp_rotator_session *rot;
  37. int i;
  38. for (i = 0; i < MAX_ROTATOR_SESSIONS; i++) {
  39. rot = &rotator_session[i];
  40. if (rot->ref_cnt == 0) {
  41. rot->ref_cnt++;
  42. rot->session_id = i | MDSS_MDP_ROT_SESSION_MASK;
  43. mutex_init(&rot->lock);
  44. INIT_LIST_HEAD(&rot->head);
  45. INIT_LIST_HEAD(&rot->list);
  46. break;
  47. }
  48. }
  49. if (i == MAX_ROTATOR_SESSIONS) {
  50. pr_err("max rotator sessions reached\n");
  51. return NULL;
  52. }
  53. return rot;
  54. }
  55. static inline struct mdss_mdp_rotator_session
  56. *mdss_mdp_rotator_session_get(u32 session_id)
  57. {
  58. struct mdss_mdp_rotator_session *rot;
  59. u32 ndx;
  60. ndx = session_id & ~MDSS_MDP_ROT_SESSION_MASK;
  61. if (ndx < MAX_ROTATOR_SESSIONS) {
  62. rot = &rotator_session[ndx];
  63. if (rot->ref_cnt && rot->session_id == session_id)
  64. return rot;
  65. }
  66. return NULL;
  67. }
  68. struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_get(
  69. struct msm_fb_data_type *mfd, const struct mdp_buf_sync *buf_sync)
  70. {
  71. struct mdss_mdp_rotator_session *rot;
  72. rot = mdss_mdp_rotator_session_get(buf_sync->session_id);
  73. if (!rot)
  74. return NULL;
  75. if (!rot->rot_sync_pt_data)
  76. rot->rot_sync_pt_data = mdss_mdp_rotator_sync_pt_create(rot);
  77. if (rot->rot_sync_pt_data)
  78. rot->use_sync_pt = true;
  79. return rot->rot_sync_pt_data;
  80. }
  81. static struct mdss_mdp_pipe *mdss_mdp_rotator_pipe_alloc(void)
  82. {
  83. struct mdss_mdp_mixer *mixer;
  84. struct mdss_mdp_pipe *pipe = NULL;
  85. mixer = mdss_mdp_wb_mixer_alloc(1);
  86. if (!mixer) {
  87. pr_err("wb mixer alloc failed\n");
  88. return NULL;
  89. }
  90. pipe = mdss_mdp_pipe_alloc_dma(mixer);
  91. if (!pipe) {
  92. mdss_mdp_wb_mixer_destroy(mixer);
  93. pr_err("dma pipe allocation failed\n");
  94. return NULL;
  95. }
  96. pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;
  97. return pipe;
  98. }
  99. static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot)
  100. {
  101. mutex_lock(&rot->lock);
  102. if (!rot->pipe || !rot->pipe->mixer || !rot->pipe->mixer->ctl) {
  103. mutex_unlock(&rot->lock);
  104. return -ENODEV;
  105. }
  106. if (rot->busy) {
  107. struct mdss_mdp_ctl *ctl = rot->pipe->mixer->ctl;
  108. mdss_mdp_display_wait4comp(ctl);
  109. rot->busy = false;
  110. if (ctl->shared_lock)
  111. mutex_unlock(ctl->shared_lock);
  112. }
  113. mutex_unlock(&rot->lock);
  114. return 0;
  115. }
  116. static int mdss_mdp_rotator_kickoff(struct mdss_mdp_ctl *ctl,
  117. struct mdss_mdp_rotator_session *rot,
  118. struct mdss_mdp_data *dst_data)
  119. {
  120. int ret;
  121. struct mdss_mdp_writeback_arg wb_args = {
  122. .data = dst_data,
  123. .priv_data = rot,
  124. };
  125. mutex_lock(&rot->lock);
  126. rot->busy = true;
  127. ret = mdss_mdp_writeback_display_commit(ctl, &wb_args);
  128. if (ret) {
  129. rot->busy = false;
  130. pr_err("problem with kickoff rot pipe=%d", rot->pipe->num);
  131. }
  132. mutex_unlock(&rot->lock);
  133. return ret;
  134. }
  135. static int mdss_mdp_rotator_pipe_dequeue(struct mdss_mdp_rotator_session *rot)
  136. {
  137. int rc;
  138. if (rot->pipe) {
  139. pr_debug("reusing existing session=%d\n", rot->pipe->num);
  140. mdss_mdp_rotator_busy_wait(rot);
  141. list_move_tail(&rot->head, &rotator_queue);
  142. } else {
  143. struct mdss_mdp_rotator_session *tmp;
  144. rot->params_changed++;
  145. rot->pipe = mdss_mdp_rotator_pipe_alloc();
  146. if (rot->pipe) {
  147. pr_debug("use new rotator pipe=%d\n", rot->pipe->num);
  148. list_add_tail(&rot->head, &rotator_queue);
  149. } else if (!list_empty(&rotator_queue)) {
  150. tmp = list_first_entry(&rotator_queue,
  151. struct mdss_mdp_rotator_session,
  152. head);
  153. rc = mdss_mdp_rotator_busy_wait(tmp);
  154. mdss_mdp_smp_release(tmp->pipe);
  155. list_del(&tmp->head);
  156. if (rc) {
  157. pr_err("no pipe attached to session=%d\n",
  158. tmp->session_id);
  159. return rc;
  160. } else {
  161. pr_debug("waited for rotator pipe=%d\n",
  162. tmp->pipe->num);
  163. }
  164. rot->pipe = tmp->pipe;
  165. tmp->pipe = NULL;
  166. list_add_tail(&rot->head, &rotator_queue);
  167. } else {
  168. pr_err("no available rotator pipes\n");
  169. return -EBUSY;
  170. }
  171. }
  172. return 0;
  173. }
  174. /**
  175. * __mdss_mdp_rotator_to_pipe() - setup pipe according to rotator session params
  176. * @rot: Pointer to rotator session
  177. * @pipe: Pointer to pipe driving structure
  178. *
  179. * After calling this the pipe structure will contain all parameters required
  180. * to use rotator pipe. Note that this function assumes rotator pipe is idle.
  181. */
  182. static int __mdss_mdp_rotator_to_pipe(struct mdss_mdp_rotator_session *rot,
  183. struct mdss_mdp_pipe *pipe)
  184. {
  185. int ret;
  186. struct mdss_mdp_pipe *rot_pipe = NULL;
  187. struct mdss_mdp_ctl *orig_ctl;
  188. rot_pipe = rot->pipe;
  189. orig_ctl = rot_pipe->mixer->ctl;
  190. if (orig_ctl->wb_lock)
  191. mutex_lock(orig_ctl->wb_lock);
  192. pipe->flags = rot->flags;
  193. pipe->src_fmt = mdss_mdp_get_format_params(rot->format);
  194. pipe->img_width = rot->img_width;
  195. pipe->img_height = rot->img_height;
  196. pipe->src = rot->src_rect;
  197. pipe->dst = rot->src_rect;
  198. pipe->dst.x = 0;
  199. pipe->dst.y = 0;
  200. pipe->params_changed++;
  201. rot->params_changed = 0;
  202. ret = mdss_mdp_smp_reserve(pipe);
  203. if (ret)
  204. pr_debug("unable to mdss_mdp_smp_reserve rot data\n");
  205. if (orig_ctl->wb_lock)
  206. mutex_unlock(orig_ctl->wb_lock);
  207. return ret;
  208. }
  209. static int mdss_mdp_rotator_queue_sub(struct mdss_mdp_rotator_session *rot,
  210. struct mdss_mdp_data *src_data,
  211. struct mdss_mdp_data *dst_data)
  212. {
  213. struct mdss_mdp_pipe *rot_pipe = NULL;
  214. struct mdss_mdp_ctl *orig_ctl, *rot_ctl;
  215. int ret;
  216. if (!rot || !rot->ref_cnt)
  217. return -ENOENT;
  218. ret = mdss_mdp_rotator_pipe_dequeue(rot);
  219. if (ret) {
  220. pr_err("unable to acquire rotator\n");
  221. return ret;
  222. }
  223. rot_pipe = rot->pipe;
  224. pr_debug("queue rotator pnum=%d\n", rot_pipe->num);
  225. orig_ctl = rot_pipe->mixer->ctl;
  226. if (orig_ctl->shared_lock)
  227. mutex_lock(orig_ctl->shared_lock);
  228. rot_ctl = mdss_mdp_ctl_mixer_switch(orig_ctl,
  229. MDSS_MDP_WB_CTL_TYPE_BLOCK);
  230. if (!rot_ctl) {
  231. ret = -EINVAL;
  232. goto error;
  233. } else {
  234. rot->pipe->mixer = rot_ctl->mixer_left;
  235. }
  236. if (rot->params_changed || rot_ctl->mdata->mixer_switched) {
  237. ret = __mdss_mdp_rotator_to_pipe(rot, rot_pipe);
  238. if (ret) {
  239. pr_err("rotator session=%x to pipe=%d failed %d\n",
  240. rot->session_id, rot_pipe->num, ret);
  241. goto error;
  242. }
  243. }
  244. ret = mdss_mdp_pipe_queue_data(rot_pipe, src_data);
  245. if (ret) {
  246. pr_err("unable to queue rot data\n");
  247. goto error;
  248. }
  249. ATRACE_BEGIN("rotator_kickoff");
  250. ret = mdss_mdp_rotator_kickoff(rot_ctl, rot, dst_data);
  251. ATRACE_END("rotator_kickoff");
  252. if (ret) {
  253. pr_err("mdss_mdp_rotator_kickoff error : %d\n", ret);
  254. goto error;
  255. }
  256. return ret;
  257. error:
  258. if (orig_ctl->shared_lock)
  259. mutex_unlock(orig_ctl->shared_lock);
  260. return ret;
  261. }
  262. static void mdss_mdp_rotator_commit_wq_handler(struct work_struct *work)
  263. {
  264. struct mdss_mdp_rotator_session *rot;
  265. int ret;
  266. rot = container_of(work, struct mdss_mdp_rotator_session, commit_work);
  267. mutex_lock(&rotator_lock);
  268. ret = mdss_mdp_rotator_queue_helper(rot);
  269. if (ret)
  270. pr_err("rotator queue failed\n");
  271. if (rot->rot_sync_pt_data) {
  272. atomic_inc(&rot->rot_sync_pt_data->commit_cnt);
  273. mdss_fb_signal_timeline(rot->rot_sync_pt_data);
  274. } else {
  275. pr_err("rot_sync_pt_data is NULL\n");
  276. }
  277. mutex_unlock(&rotator_lock);
  278. }
  279. static struct msm_sync_pt_data *mdss_mdp_rotator_sync_pt_create(
  280. struct mdss_mdp_rotator_session *rot)
  281. {
  282. struct msm_sync_pt_data *sync_pt_data;
  283. char timeline_name[16];
  284. rot->rot_sync_pt_data = kzalloc(
  285. sizeof(struct msm_sync_pt_data), GFP_KERNEL);
  286. sync_pt_data = rot->rot_sync_pt_data;
  287. if (!sync_pt_data)
  288. return NULL;
  289. sync_pt_data->fence_name = "rot-fence";
  290. sync_pt_data->threshold = 1;
  291. snprintf(timeline_name, sizeof(timeline_name),
  292. "mdss_rot_%d", rot->session_id);
  293. sync_pt_data->timeline = sw_sync_timeline_create(timeline_name);
  294. if (sync_pt_data->timeline == NULL) {
  295. kfree(rot->rot_sync_pt_data);
  296. pr_err("%s: cannot create time line", __func__);
  297. return NULL;
  298. } else {
  299. sync_pt_data->timeline_value = 0;
  300. }
  301. INIT_WORK(&rot->commit_work,
  302. mdss_mdp_rotator_commit_wq_handler);
  303. mutex_init(&sync_pt_data->sync_mutex);
  304. return sync_pt_data;
  305. }
  306. static int mdss_mdp_rotator_busy_wait_ex(struct mdss_mdp_rotator_session *rot)
  307. {
  308. struct mdss_mdp_rotator_session *tmp;
  309. for (tmp = rot; tmp; tmp = tmp->next)
  310. mdss_mdp_rotator_busy_wait(tmp);
  311. if (rot->use_sync_pt)
  312. mdss_fb_wait_for_fence(rot->rot_sync_pt_data);
  313. return 0;
  314. }
  315. static int mdss_mdp_rotator_queue_helper(struct mdss_mdp_rotator_session *rot)
  316. {
  317. int ret;
  318. struct mdss_mdp_rotator_session *tmp;
  319. pr_debug("rotator session=%x start\n", rot->session_id);
  320. for (ret = 0, tmp = rot; ret == 0 && tmp; tmp = tmp->next)
  321. ret = mdss_mdp_rotator_queue_sub(tmp,
  322. &rot->src_buf, &rot->dst_buf);
  323. if (ret) {
  324. pr_err("rotation failed %d for rot=%d\n", ret, rot->session_id);
  325. return ret;
  326. }
  327. for (tmp = rot; tmp; tmp = tmp->next)
  328. mdss_mdp_rotator_busy_wait(tmp);
  329. return ret;
  330. }
  331. static int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot)
  332. {
  333. int ret = 0;
  334. if (rot->use_sync_pt)
  335. schedule_work(&rot->commit_work);
  336. else
  337. ret = mdss_mdp_rotator_queue_helper(rot);
  338. pr_debug("rotator session=%x queue done\n", rot->session_id);
  339. return ret;
  340. }
  341. /*
  342. * Try to reserve hardware resources for rotator session if possible, if this
  343. * is not possible we may still have a chance to reuse existing pipes used by
  344. * other sessions at a later point.
  345. */
  346. static int __mdss_mdp_rotator_pipe_reserve(struct mdss_mdp_rotator_session *rot)
  347. {
  348. int ret;
  349. if (!rot->pipe) {
  350. rot->pipe = mdss_mdp_rotator_pipe_alloc();
  351. if (rot->pipe) {
  352. pr_debug("reserved rotator pipe=%d\n", rot->pipe->num);
  353. list_add_tail(&rot->head, &rotator_queue);
  354. } else {
  355. /*
  356. * if rotator queue is not empty means that we'll be
  357. * able to reuse existing rotator pipes for this rotator
  358. * session, otherwise it means that there are no DMA
  359. * pipes available so we should abort now
  360. */
  361. if (list_empty(&rotator_queue)) {
  362. pr_err("unable to reserve rot pipe\n");
  363. return -ENODEV;
  364. }
  365. pr_debug("unable to get rot pipe but some in queue\n");
  366. return 0;
  367. }
  368. }
  369. ret = __mdss_mdp_rotator_to_pipe(rot, rot->pipe);
  370. if (ret)
  371. pr_err("rotator session=%x to pipe=%d failed %d\n",
  372. rot->session_id, rot->pipe->num, ret);
  373. return ret;
  374. }
  375. int mdss_mdp_rotator_setup(struct msm_fb_data_type *mfd,
  376. struct mdp_overlay *req)
  377. {
  378. struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
  379. struct mdss_mdp_rotator_session *rot = NULL;
  380. struct mdss_mdp_format_params *fmt;
  381. u32 bwc_enabled;
  382. bool format_changed = false;
  383. int ret = 0;
  384. mutex_lock(&rotator_lock);
  385. fmt = mdss_mdp_get_format_params(req->src.format);
  386. if (!fmt) {
  387. pr_err("invalid rot format %d\n", req->src.format);
  388. ret = -EINVAL;
  389. goto rot_err;
  390. }
  391. ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
  392. if (ret)
  393. goto rot_err;
  394. if (req->id == MSMFB_NEW_REQUEST) {
  395. rot = mdss_mdp_rotator_session_alloc();
  396. if (!rot) {
  397. pr_err("unable to allocate rotator session\n");
  398. ret = -ENOMEM;
  399. goto rot_err;
  400. }
  401. rot->pid = current->tgid;
  402. list_add(&rot->list, &mdp5_data->rot_proc_list);
  403. } else if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
  404. rot = mdss_mdp_rotator_session_get(req->id);
  405. if (!rot) {
  406. pr_err("rotator session=%x not found\n", req->id);
  407. ret = -ENODEV;
  408. goto rot_err;
  409. }
  410. if (work_busy(&rot->commit_work)) {
  411. mutex_unlock(&rotator_lock);
  412. flush_work(&rot->commit_work);
  413. mutex_lock(&rotator_lock);
  414. }
  415. if (rot->format != fmt->format)
  416. format_changed = true;
  417. } else {
  418. pr_err("invalid rotator session id=%x\n", req->id);
  419. ret = -EINVAL;
  420. goto rot_err;
  421. }
  422. /* keep only flags of interest to rotator */
  423. rot->flags = req->flags & (MDP_ROT_90 | MDP_FLIP_LR | MDP_FLIP_UD |
  424. MDP_SECURE_OVERLAY_SESSION);
  425. bwc_enabled = req->flags & MDP_BWC_EN;
  426. if (bwc_enabled && !mdp5_data->mdata->has_bwc) {
  427. pr_err("BWC is not supported in MDP version %x\n",
  428. mdp5_data->mdata->mdp_rev);
  429. rot->bwc_mode = 0;
  430. } else {
  431. rot->bwc_mode = bwc_enabled ? 1 : 0;
  432. }
  433. rot->format = fmt->format;
  434. rot->img_width = req->src.width;
  435. rot->img_height = req->src.height;
  436. rot->src_rect.x = req->src_rect.x;
  437. rot->src_rect.y = req->src_rect.y;
  438. rot->src_rect.w = req->src_rect.w;
  439. rot->src_rect.h = req->src_rect.h;
  440. if (req->flags & MDP_DEINTERLACE) {
  441. rot->flags |= MDP_DEINTERLACE;
  442. rot->src_rect.h /= 2;
  443. rot->src_rect.y = DIV_ROUND_UP(rot->src_rect.y, 2);
  444. rot->src_rect.y &= ~1;
  445. }
  446. rot->dst = rot->src_rect;
  447. /*
  448. * by default, rotator output should be placed directly on
  449. * output buffer address without any offset.
  450. */
  451. rot->dst.x = 0;
  452. rot->dst.y = 0;
  453. if (rot->flags & MDP_ROT_90)
  454. swap(rot->dst.w, rot->dst.h);
  455. if (rot->src_rect.w > MAX_MIXER_WIDTH) {
  456. struct mdss_mdp_rotator_session *tmp;
  457. u32 width;
  458. if (rot->bwc_mode) {
  459. pr_err("Unable to do split rotation with bwc set\n");
  460. ret = -EINVAL;
  461. goto rot_err;
  462. }
  463. width = rot->src_rect.w;
  464. pr_debug("setting up split rotation src=%dx%d\n",
  465. rot->src_rect.w, rot->src_rect.h);
  466. if (width > (MAX_MIXER_WIDTH * 2)) {
  467. pr_err("unsupported source width %d\n", width);
  468. ret = -EOVERFLOW;
  469. goto rot_err;
  470. }
  471. if (!rot->next) {
  472. tmp = mdss_mdp_rotator_session_alloc();
  473. if (!tmp) {
  474. pr_err("unable to allocate rot dual session\n");
  475. ret = -ENOMEM;
  476. goto rot_err;
  477. }
  478. rot->next = tmp;
  479. }
  480. tmp = rot->next;
  481. tmp->session_id = rot->session_id & ~MDSS_MDP_ROT_SESSION_MASK;
  482. tmp->flags = rot->flags;
  483. tmp->format = rot->format;
  484. tmp->img_width = rot->img_width;
  485. tmp->img_height = rot->img_height;
  486. tmp->src_rect = rot->src_rect;
  487. tmp->src_rect.w = width / 2;
  488. width -= tmp->src_rect.w;
  489. tmp->src_rect.x += width;
  490. tmp->dst = rot->dst;
  491. rot->src_rect.w = width;
  492. if (rot->flags & MDP_ROT_90) {
  493. /*
  494. * If rotated by 90 first half should be on top.
  495. * But if horizontally flipped should be on bottom.
  496. */
  497. if (rot->flags & MDP_FLIP_LR)
  498. rot->dst.y = tmp->src_rect.w;
  499. else
  500. tmp->dst.y = rot->src_rect.w;
  501. } else {
  502. /*
  503. * If not rotated, first half should be the left part
  504. * of the frame, unless horizontally flipped
  505. */
  506. if (rot->flags & MDP_FLIP_LR)
  507. rot->dst.x = tmp->src_rect.w;
  508. else
  509. tmp->dst.x = rot->src_rect.w;
  510. }
  511. tmp->params_changed++;
  512. } else if (rot->next) {
  513. mdss_mdp_rotator_finish(rot->next);
  514. rot->next = NULL;
  515. }
  516. rot->params_changed++;
  517. /* If the format changed, release the smp alloc */
  518. if (format_changed && rot->pipe) {
  519. mdss_mdp_rotator_busy_wait(rot);
  520. mdss_mdp_smp_release(rot->pipe);
  521. }
  522. ret = __mdss_mdp_rotator_pipe_reserve(rot);
  523. if (!ret && rot->next)
  524. ret = __mdss_mdp_rotator_pipe_reserve(rot->next);
  525. if (ret)
  526. goto rot_err;
  527. req->id = rot->session_id;
  528. rot_err:
  529. if (ret) {
  530. pr_err("Unable to setup rotator session\n");
  531. if (rot && (req->id == MSMFB_NEW_REQUEST))
  532. mdss_mdp_rotator_finish(rot);
  533. }
  534. /*
  535. * overwrite the src format for rotator to dst format
  536. * for use by the user. On subsequent set calls, the
  537. * user is expected to proivde the original src format
  538. */
  539. req->src.format = mdss_mdp_get_rotator_dst_format(req->src.format,
  540. req->flags & MDP_ROT_90);
  541. mutex_unlock(&rotator_lock);
  542. return ret;
  543. }
  544. static int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot)
  545. {
  546. struct mdss_mdp_pipe *rot_pipe;
  547. struct mdss_mdp_ctl *tmp;
  548. int ret = 0;
  549. struct msm_sync_pt_data *rot_sync_pt_data;
  550. struct work_struct commit_work;
  551. if (!rot)
  552. return -ENODEV;
  553. pr_debug("finish rot id=%x\n", rot->session_id);
  554. if (rot->next)
  555. mdss_mdp_rotator_finish(rot->next);
  556. rot_pipe = rot->pipe;
  557. if (rot_pipe) {
  558. if (work_busy(&rot->commit_work)) {
  559. mutex_unlock(&rotator_lock);
  560. flush_work(&rot->commit_work);
  561. mutex_lock(&rotator_lock);
  562. }
  563. mdss_mdp_rotator_busy_wait(rot);
  564. list_del(&rot->head);
  565. }
  566. if (!list_empty(&rot->list))
  567. list_del(&rot->list);
  568. rot_sync_pt_data = rot->rot_sync_pt_data;
  569. commit_work = rot->commit_work;
  570. memset(rot, 0, sizeof(*rot));
  571. rot->rot_sync_pt_data = rot_sync_pt_data;
  572. rot->commit_work = commit_work;
  573. if (rot_pipe) {
  574. struct mdss_mdp_mixer *mixer = rot_pipe->mixer;
  575. mdss_mdp_pipe_destroy(rot_pipe);
  576. tmp = mdss_mdp_ctl_mixer_switch(mixer->ctl,
  577. MDSS_MDP_WB_CTL_TYPE_BLOCK);
  578. if (!tmp)
  579. return -EINVAL;
  580. else
  581. mixer = tmp->mixer_left;
  582. mdss_mdp_wb_mixer_destroy(mixer);
  583. }
  584. return ret;
  585. }
  586. int mdss_mdp_rotator_release(struct mdss_mdp_rotator_session *rot)
  587. {
  588. int rc = 0;
  589. mutex_lock(&rotator_lock);
  590. rc = mdss_mdp_rotator_finish(rot);
  591. mutex_unlock(&rotator_lock);
  592. return rc;
  593. }
  594. int mdss_mdp_rotator_release_all(void)
  595. {
  596. struct mdss_mdp_rotator_session *rot;
  597. int i, cnt;
  598. mutex_lock(&rotator_lock);
  599. for (i = 0, cnt = 0; i < MAX_ROTATOR_SESSIONS; i++) {
  600. rot = &rotator_session[i];
  601. if (rot->ref_cnt) {
  602. mdss_mdp_rotator_finish(rot);
  603. cnt++;
  604. }
  605. }
  606. mutex_unlock(&rotator_lock);
  607. if (cnt)
  608. pr_debug("cleaned up %d rotator sessions\n", cnt);
  609. return 0;
  610. }
  611. int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd,
  612. struct msmfb_overlay_data *req)
  613. {
  614. struct mdss_mdp_rotator_session *rot;
  615. int ret;
  616. u32 flgs;
  617. mutex_lock(&rotator_lock);
  618. rot = mdss_mdp_rotator_session_get(req->id);
  619. if (!rot) {
  620. pr_err("invalid session id=%x\n", req->id);
  621. ret = -ENOENT;
  622. goto dst_buf_fail;
  623. }
  624. flgs = rot->flags & MDP_SECURE_OVERLAY_SESSION;
  625. ret = mdss_mdp_rotator_busy_wait_ex(rot);
  626. if (ret) {
  627. pr_err("rotator busy wait error\n");
  628. goto dst_buf_fail;
  629. }
  630. mdss_mdp_overlay_free_buf(&rot->src_buf);
  631. ret = mdss_mdp_overlay_get_buf(mfd, &rot->src_buf, &req->data, 1, flgs);
  632. if (ret) {
  633. pr_err("src_data pmem error\n");
  634. goto dst_buf_fail;
  635. }
  636. mdss_mdp_overlay_free_buf(&rot->dst_buf);
  637. ret = mdss_mdp_overlay_get_buf(mfd, &rot->dst_buf,
  638. &req->dst_data, 1, flgs);
  639. if (ret) {
  640. pr_err("dst_data pmem error\n");
  641. goto dst_buf_fail;
  642. }
  643. ret = mdss_mdp_rotator_queue(rot);
  644. if (ret)
  645. pr_err("rotator queue error session id=%x\n", req->id);
  646. dst_buf_fail:
  647. if(ret){
  648. if (rot && rot->use_sync_pt){
  649. if (rot->rot_sync_pt_data) {
  650. atomic_inc(&rot->rot_sync_pt_data->commit_cnt);
  651. mdss_fb_signal_timeline(rot->rot_sync_pt_data);
  652. pr_err("release fence as this commit is failed.\n");
  653. } else {
  654. pr_err("rot_sync_pt_data is NULL\n");
  655. }
  656. }
  657. }
  658. mutex_unlock(&rotator_lock);
  659. return ret;
  660. }
  661. int mdss_mdp_rotator_unset(int ndx)
  662. {
  663. struct mdss_mdp_rotator_session *rot;
  664. int ret = 0;
  665. mutex_lock(&rotator_lock);
  666. rot = mdss_mdp_rotator_session_get(ndx);
  667. if (rot) {
  668. mdss_mdp_overlay_free_buf(&rot->src_buf);
  669. mdss_mdp_overlay_free_buf(&rot->dst_buf);
  670. rot->pid = 0;
  671. ret = mdss_mdp_rotator_finish(rot);
  672. }
  673. mutex_unlock(&rotator_lock);
  674. return ret;
  675. }