mdss_mdp_util.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /* Copyright (c) 2012-2014, 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/dma-mapping.h>
  15. #include <linux/errno.h>
  16. #include <linux/file.h>
  17. #include <linux/msm_ion.h>
  18. #include <linux/iommu.h>
  19. #include <linux/msm_kgsl.h>
  20. #include <linux/spinlock.h>
  21. #include <linux/types.h>
  22. #include <media/msm_media_info.h>
  23. #include <mach/iommu_domains.h>
  24. #include "mdss_fb.h"
  25. #include "mdss_mdp.h"
  26. #include "mdss_mdp_formats.h"
  27. #include "mdss_debug.h"
  28. enum {
  29. MDP_INTR_VSYNC_INTF_0,
  30. MDP_INTR_VSYNC_INTF_1,
  31. MDP_INTR_VSYNC_INTF_2,
  32. MDP_INTR_VSYNC_INTF_3,
  33. MDP_INTR_UNDERRUN_INTF_0,
  34. MDP_INTR_UNDERRUN_INTF_1,
  35. MDP_INTR_UNDERRUN_INTF_2,
  36. MDP_INTR_UNDERRUN_INTF_3,
  37. MDP_INTR_PING_PONG_0,
  38. MDP_INTR_PING_PONG_1,
  39. MDP_INTR_PING_PONG_2,
  40. MDP_INTR_PING_PONG_3,
  41. MDP_INTR_PING_PONG_0_RD_PTR,
  42. MDP_INTR_PING_PONG_1_RD_PTR,
  43. MDP_INTR_PING_PONG_2_RD_PTR,
  44. MDP_INTR_PING_PONG_3_RD_PTR,
  45. MDP_INTR_WB_0,
  46. MDP_INTR_WB_1,
  47. MDP_INTR_WB_2,
  48. MDP_INTR_MAX,
  49. };
  50. struct intr_callback {
  51. void (*func)(void *);
  52. void *arg;
  53. };
  54. struct intr_callback mdp_intr_cb[MDP_INTR_MAX];
  55. static DEFINE_SPINLOCK(mdss_mdp_intr_lock);
  56. static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num)
  57. {
  58. int index = -1;
  59. switch (intr_type) {
  60. case MDSS_MDP_IRQ_INTF_UNDER_RUN:
  61. index = MDP_INTR_UNDERRUN_INTF_0 + (intf_num - MDSS_MDP_INTF0);
  62. break;
  63. case MDSS_MDP_IRQ_INTF_VSYNC:
  64. index = MDP_INTR_VSYNC_INTF_0 + (intf_num - MDSS_MDP_INTF0);
  65. break;
  66. case MDSS_MDP_IRQ_PING_PONG_COMP:
  67. index = MDP_INTR_PING_PONG_0 + intf_num;
  68. break;
  69. case MDSS_MDP_IRQ_PING_PONG_RD_PTR:
  70. index = MDP_INTR_PING_PONG_0_RD_PTR + intf_num;
  71. break;
  72. case MDSS_MDP_IRQ_WB_ROT_COMP:
  73. index = MDP_INTR_WB_0 + intf_num;
  74. break;
  75. case MDSS_MDP_IRQ_WB_WFD:
  76. index = MDP_INTR_WB_2 + intf_num;
  77. break;
  78. }
  79. return index;
  80. }
  81. int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
  82. void (*fnc_ptr)(void *), void *arg)
  83. {
  84. unsigned long flags;
  85. int index;
  86. index = mdss_mdp_intr2index(intr_type, intf_num);
  87. if (index < 0) {
  88. pr_warn("invalid intr type=%u intf_num=%u\n",
  89. intr_type, intf_num);
  90. return -EINVAL;
  91. }
  92. spin_lock_irqsave(&mdss_mdp_intr_lock, flags);
  93. WARN(mdp_intr_cb[index].func && fnc_ptr,
  94. "replacing current intr callback for ndx=%d\n", index);
  95. mdp_intr_cb[index].func = fnc_ptr;
  96. mdp_intr_cb[index].arg = arg;
  97. spin_unlock_irqrestore(&mdss_mdp_intr_lock, flags);
  98. return 0;
  99. }
  100. static inline void mdss_mdp_intr_done(int index)
  101. {
  102. void (*fnc)(void *);
  103. void *arg;
  104. spin_lock(&mdss_mdp_intr_lock);
  105. fnc = mdp_intr_cb[index].func;
  106. arg = mdp_intr_cb[index].arg;
  107. spin_unlock(&mdss_mdp_intr_lock);
  108. if (fnc)
  109. fnc(arg);
  110. }
  111. irqreturn_t mdss_mdp_isr(int irq, void *ptr)
  112. {
  113. struct mdss_data_type *mdata = ptr;
  114. u32 isr, hist_isr, hist_mask;
  115. u32 mask = 0;
  116. isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
  117. #if 0//defined (CONFIG_FB_MSM_MDSS_DSI_DBG)
  118. xlog(__func__, 0, isr, mask, 0, 0, 0);
  119. #endif
  120. if (isr == 0)
  121. goto mdp_isr_done;
  122. mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
  123. MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
  124. pr_debug("%s: isr=%x mask=%x\n", __func__, isr, mask);
  125. isr &= mask;
  126. if (isr == 0)
  127. goto mdp_isr_done;
  128. if (isr & MDSS_MDP_INTR_INTF_0_UNDERRUN)
  129. mdss_mdp_intr_done(MDP_INTR_UNDERRUN_INTF_0);
  130. if (isr & MDSS_MDP_INTR_INTF_1_UNDERRUN)
  131. mdss_mdp_intr_done(MDP_INTR_UNDERRUN_INTF_1);
  132. if (isr & MDSS_MDP_INTR_INTF_2_UNDERRUN)
  133. mdss_mdp_intr_done(MDP_INTR_UNDERRUN_INTF_2);
  134. if (isr & MDSS_MDP_INTR_INTF_3_UNDERRUN)
  135. mdss_mdp_intr_done(MDP_INTR_UNDERRUN_INTF_3);
  136. if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
  137. mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
  138. if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE)
  139. mdss_mdp_intr_done(MDP_INTR_PING_PONG_1);
  140. if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
  141. mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
  142. if (isr & MDSS_MDP_INTR_PING_PONG_3_DONE)
  143. mdss_mdp_intr_done(MDP_INTR_PING_PONG_3);
  144. if (isr & MDSS_MDP_INTR_PING_PONG_0_RD_PTR)
  145. mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_RD_PTR);
  146. if (isr & MDSS_MDP_INTR_PING_PONG_1_RD_PTR)
  147. mdss_mdp_intr_done(MDP_INTR_PING_PONG_1_RD_PTR);
  148. if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
  149. mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
  150. if (isr & MDSS_MDP_INTR_PING_PONG_3_RD_PTR)
  151. mdss_mdp_intr_done(MDP_INTR_PING_PONG_3_RD_PTR);
  152. if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) {
  153. mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
  154. mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP);
  155. }
  156. if (isr & MDSS_MDP_INTR_INTF_1_VSYNC) {
  157. mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
  158. mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0);
  159. }
  160. if (isr & MDSS_MDP_INTR_INTF_2_VSYNC) {
  161. mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
  162. mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1);
  163. }
  164. if (isr & MDSS_MDP_INTR_INTF_3_VSYNC) {
  165. mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
  166. mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
  167. }
  168. if (isr & MDSS_MDP_INTR_WB_0_DONE) {
  169. mdss_mdp_intr_done(MDP_INTR_WB_0);
  170. mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
  171. }
  172. if (isr & MDSS_MDP_INTR_WB_1_DONE) {
  173. mdss_mdp_intr_done(MDP_INTR_WB_1);
  174. mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
  175. }
  176. if (isr & MDSS_MDP_INTR_WB_2_DONE) {
  177. mdss_mdp_intr_done(MDP_INTR_WB_2);
  178. mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
  179. }
  180. mdp_isr_done:
  181. hist_isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_STATUS);
  182. if (hist_isr == 0)
  183. goto hist_isr_done;
  184. hist_mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_EN);
  185. MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_CLEAR, hist_isr);
  186. hist_isr &= hist_mask;
  187. if (hist_isr == 0)
  188. goto hist_isr_done;
  189. mdss_mdp_hist_intr_done(hist_isr);
  190. hist_isr_done:
  191. return IRQ_HANDLED;
  192. }
  193. struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format)
  194. {
  195. if (format < MDP_IMGTYPE_LIMIT) {
  196. struct mdss_mdp_format_params *fmt = NULL;
  197. int i;
  198. for (i = 0; i < ARRAY_SIZE(mdss_mdp_format_map); i++) {
  199. fmt = &mdss_mdp_format_map[i];
  200. if (format == fmt->format)
  201. return fmt;
  202. }
  203. }
  204. return NULL;
  205. }
  206. void mdss_mdp_intersect_rect(struct mdss_mdp_img_rect *res_rect,
  207. const struct mdss_mdp_img_rect *dst_rect,
  208. const struct mdss_mdp_img_rect *sci_rect)
  209. {
  210. int l = max(dst_rect->x, sci_rect->x);
  211. int t = max(dst_rect->y, sci_rect->y);
  212. int r = min((dst_rect->x + dst_rect->w), (sci_rect->x + sci_rect->w));
  213. int b = min((dst_rect->y + dst_rect->h), (sci_rect->y + sci_rect->h));
  214. if (r < l || b < t)
  215. *res_rect = (struct mdss_mdp_img_rect){0, 0, 0, 0};
  216. else
  217. *res_rect = (struct mdss_mdp_img_rect){l, t, (r-l), (b-t)};
  218. }
  219. void mdss_mdp_crop_rect(struct mdss_mdp_img_rect *src_rect,
  220. struct mdss_mdp_img_rect *dst_rect,
  221. const struct mdss_mdp_img_rect *sci_rect)
  222. {
  223. struct mdss_mdp_img_rect res;
  224. mdss_mdp_intersect_rect(&res, dst_rect, sci_rect);
  225. if (res.w && res.h) {
  226. if ((res.w != dst_rect->w) || (res.h != dst_rect->h)) {
  227. src_rect->x = src_rect->x + (res.x - dst_rect->x);
  228. src_rect->y = src_rect->y + (res.y - dst_rect->y);
  229. src_rect->w = res.w;
  230. src_rect->h = res.h;
  231. }
  232. *dst_rect = (struct mdss_mdp_img_rect)
  233. {(res.x - sci_rect->x), (res.y - sci_rect->y),
  234. res.w, res.h};
  235. }
  236. }
  237. int mdss_mdp_get_rau_strides(u32 w, u32 h,
  238. struct mdss_mdp_format_params *fmt,
  239. struct mdss_mdp_plane_sizes *ps)
  240. {
  241. if (fmt->is_yuv) {
  242. ps->rau_cnt = DIV_ROUND_UP(w, 64);
  243. ps->ystride[0] = 64 * 4;
  244. ps->rau_h[0] = 4;
  245. ps->rau_h[1] = 2;
  246. if (fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)
  247. ps->ystride[1] = 64 * 2;
  248. else if (fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1) {
  249. ps->ystride[1] = 32 * 4;
  250. ps->rau_h[1] = 4;
  251. } else
  252. ps->ystride[1] = 32 * 2;
  253. /* account for both chroma components */
  254. ps->ystride[1] <<= 1;
  255. } else if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
  256. ps->rau_cnt = DIV_ROUND_UP(w, 32);
  257. ps->ystride[0] = 32 * 4 * fmt->bpp;
  258. ps->ystride[1] = 0;
  259. ps->rau_h[0] = 4;
  260. ps->rau_h[1] = 0;
  261. } else {
  262. pr_err("Invalid format=%d\n", fmt->format);
  263. return -EINVAL;
  264. }
  265. ps->ystride[0] *= ps->rau_cnt;
  266. ps->ystride[1] *= ps->rau_cnt;
  267. ps->num_planes = 2;
  268. pr_debug("BWC rau_cnt=%d strides={%d,%d} heights={%d,%d}\n",
  269. ps->rau_cnt, ps->ystride[0], ps->ystride[1],
  270. ps->rau_h[0], ps->rau_h[1]);
  271. return 0;
  272. }
  273. int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
  274. struct mdss_mdp_plane_sizes *ps, u32 bwc_mode, bool rotation)
  275. {
  276. struct mdss_mdp_format_params *fmt;
  277. int i, rc;
  278. u32 bpp;
  279. if (ps == NULL)
  280. return -EINVAL;
  281. if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT))
  282. return -ERANGE;
  283. fmt = mdss_mdp_get_format_params(format);
  284. if (!fmt)
  285. return -EINVAL;
  286. bpp = fmt->bpp;
  287. memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
  288. if (bwc_mode) {
  289. u32 height, meta_size;
  290. rc = mdss_mdp_get_rau_strides(w, h, fmt, ps);
  291. if (rc)
  292. return rc;
  293. height = DIV_ROUND_UP(h, ps->rau_h[0]);
  294. meta_size = DIV_ROUND_UP(ps->rau_cnt, 8);
  295. ps->ystride[1] += meta_size;
  296. ps->ystride[0] += ps->ystride[1] + meta_size;
  297. ps->plane_size[0] = ps->ystride[0] * height;
  298. ps->ystride[1] = 2;
  299. ps->plane_size[1] = 2 * ps->rau_cnt * height;
  300. pr_debug("BWC data stride=%d size=%d meta size=%d\n",
  301. ps->ystride[0], ps->plane_size[0], ps->plane_size[1]);
  302. } else {
  303. if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
  304. ps->num_planes = 1;
  305. ps->plane_size[0] = w * h * bpp;
  306. ps->ystride[0] = w * bpp;
  307. } else if (format == MDP_Y_CBCR_H2V2_VENUS) {
  308. int cf = COLOR_FMT_NV12;
  309. ps->num_planes = 2;
  310. ps->ystride[0] = VENUS_Y_STRIDE(cf, w);
  311. ps->ystride[1] = VENUS_UV_STRIDE(cf, w);
  312. ps->plane_size[0] = VENUS_Y_SCANLINES(cf, h) *
  313. ps->ystride[0];
  314. ps->plane_size[1] = VENUS_UV_SCANLINES(cf, h) *
  315. ps->ystride[1];
  316. } else {
  317. u8 hmap[] = { 1, 2, 1, 2 };
  318. u8 vmap[] = { 1, 1, 2, 2 };
  319. u8 horiz, vert, stride_align, height_align;
  320. u32 chroma_samp;
  321. chroma_samp = fmt->chroma_sample;
  322. if (rotation) {
  323. if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
  324. chroma_samp = MDSS_MDP_CHROMA_H1V2;
  325. else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
  326. chroma_samp = MDSS_MDP_CHROMA_H2V1;
  327. }
  328. horiz = hmap[chroma_samp];
  329. vert = vmap[chroma_samp];
  330. switch (format) {
  331. case MDP_Y_CR_CB_GH2V2:
  332. stride_align = 16;
  333. height_align = 1;
  334. break;
  335. default:
  336. stride_align = 1;
  337. height_align = 1;
  338. break;
  339. }
  340. ps->ystride[0] = ALIGN(w, stride_align);
  341. ps->ystride[1] = ALIGN(w / horiz, stride_align);
  342. ps->plane_size[0] = ps->ystride[0] *
  343. ALIGN(h, height_align);
  344. ps->plane_size[1] = ps->ystride[1] * (h / vert);
  345. if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
  346. ps->num_planes = 2;
  347. ps->plane_size[1] *= 2;
  348. ps->ystride[1] *= 2;
  349. } else { /* planar */
  350. ps->num_planes = 3;
  351. ps->plane_size[2] = ps->plane_size[1];
  352. ps->ystride[2] = ps->ystride[1];
  353. }
  354. }
  355. }
  356. for (i = 0; i < ps->num_planes; i++)
  357. ps->total_size += ps->plane_size[i];
  358. return 0;
  359. }
  360. int mdss_mdp_data_check(struct mdss_mdp_data *data,
  361. struct mdss_mdp_plane_sizes *ps)
  362. {
  363. struct mdss_mdp_img_data *prev, *curr;
  364. int i;
  365. if (!ps)
  366. return 0;
  367. if (!data || data->num_planes == 0)
  368. return -ENOMEM;
  369. pr_debug("srcp0=%x len=%u frame_size=%u\n", data->p[0].addr,
  370. data->p[0].len, ps->total_size);
  371. for (i = 0; i < ps->num_planes; i++) {
  372. curr = &data->p[i];
  373. if (i >= data->num_planes) {
  374. u32 psize = ps->plane_size[i-1];
  375. prev = &data->p[i-1];
  376. if (prev->len > psize) {
  377. curr->len = prev->len - psize;
  378. prev->len = psize;
  379. }
  380. curr->addr = prev->addr + psize;
  381. }
  382. if (curr->len < ps->plane_size[i]) {
  383. pr_err("insufficient mem=%u p=%d len=%u\n",
  384. curr->len, i, ps->plane_size[i]);
  385. return -ENOMEM;
  386. }
  387. pr_debug("plane[%d] addr=%x len=%u\n", i,
  388. curr->addr, curr->len);
  389. }
  390. data->num_planes = ps->num_planes;
  391. return 0;
  392. }
  393. void mdss_mdp_data_calc_offset(struct mdss_mdp_data *data, u16 x, u16 y,
  394. struct mdss_mdp_plane_sizes *ps, struct mdss_mdp_format_params *fmt)
  395. {
  396. if ((x == 0) && (y == 0))
  397. return;
  398. data->p[0].addr += y * ps->ystride[0];
  399. if (data->num_planes == 1) {
  400. data->p[0].addr += x * fmt->bpp;
  401. } else {
  402. u8 hmap[] = { 1, 2, 1, 2 };
  403. u8 vmap[] = { 1, 1, 2, 2 };
  404. u16 xoff = x / hmap[fmt->chroma_sample];
  405. u16 yoff = y / vmap[fmt->chroma_sample];
  406. data->p[0].addr += x;
  407. data->p[1].addr += xoff + (yoff * ps->ystride[1]);
  408. if (data->num_planes == 2) /* pseudo planar */
  409. data->p[1].addr += xoff;
  410. else /* planar */
  411. data->p[2].addr += xoff + (yoff * ps->ystride[2]);
  412. }
  413. }
  414. int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
  415. {
  416. struct ion_client *iclient = mdss_get_ionclient();
  417. if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
  418. pr_debug("fb mem buf=0x%x\n", data->addr);
  419. fput_light(data->srcp_file, data->p_need);
  420. data->srcp_file = NULL;
  421. } else if (data->srcp_file) {
  422. pr_debug("pmem buf=0x%x\n", data->addr);
  423. data->srcp_file = NULL;
  424. } else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
  425. pr_debug("ion hdl=%pK buf=0x%x\n", data->srcp_ihdl, data->addr);
  426. if (!iclient) {
  427. pr_err("invalid ion client\n");
  428. return -ENOMEM;
  429. } else {
  430. if (data->mapped) {
  431. int domain;
  432. if (data->flags & MDP_SECURE_OVERLAY_SESSION)
  433. domain = MDSS_IOMMU_DOMAIN_SECURE;
  434. else
  435. domain = MDSS_IOMMU_DOMAIN_UNSECURE;
  436. ion_unmap_iommu(iclient, data->srcp_ihdl,
  437. mdss_get_iommu_domain(domain), 0);
  438. if (domain == MDSS_IOMMU_DOMAIN_SECURE) {
  439. msm_ion_unsecure_buffer(iclient,
  440. data->srcp_ihdl);
  441. }
  442. data->mapped = false;
  443. }
  444. ion_free(iclient, data->srcp_ihdl);
  445. data->srcp_ihdl = NULL;
  446. }
  447. } else {
  448. return -ENOMEM;
  449. }
  450. return 0;
  451. }
  452. int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data)
  453. {
  454. struct file *file;
  455. int ret = -EINVAL;
  456. int fb_num;
  457. unsigned long *start, *len;
  458. struct ion_client *iclient = mdss_get_ionclient();
  459. start = (unsigned long *) &data->addr;
  460. len = (unsigned long *) &data->len;
  461. data->flags |= img->flags;
  462. data->p_need = 0;
  463. if (img->flags & MDP_BLIT_SRC_GEM) {
  464. data->srcp_file = NULL;
  465. ret = kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
  466. start, len);
  467. } else if (img->flags & MDP_MEMORY_ID_TYPE_FB) {
  468. file = fget_light(img->memory_id, &data->p_need);
  469. if (file == NULL) {
  470. pr_err("invalid framebuffer file (%d)\n",
  471. img->memory_id);
  472. return -EINVAL;
  473. }
  474. data->srcp_file = file;
  475. if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
  476. fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
  477. ret = mdss_fb_get_phys_info(start, len, fb_num);
  478. if (ret)
  479. pr_err("mdss_fb_get_phys_info() failed\n");
  480. } else {
  481. pr_err("invalid FB_MAJOR\n");
  482. ret = -1;
  483. }
  484. } else if (iclient) {
  485. data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
  486. if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
  487. pr_err("error on ion_import_fd\n");
  488. ret = PTR_ERR(data->srcp_ihdl);
  489. data->srcp_ihdl = NULL;
  490. return ret;
  491. }
  492. if (is_mdss_iommu_attached()) {
  493. int domain;
  494. if (data->flags & MDP_SECURE_OVERLAY_SESSION) {
  495. domain = MDSS_IOMMU_DOMAIN_SECURE;
  496. ret = msm_ion_secure_buffer(iclient,
  497. data->srcp_ihdl, 0x2, 0);
  498. if (IS_ERR_VALUE(ret)) {
  499. ion_free(iclient, data->srcp_ihdl);
  500. pr_err("failed to secure handle (%d)\n",
  501. ret);
  502. return ret;
  503. }
  504. } else {
  505. domain = MDSS_IOMMU_DOMAIN_UNSECURE;
  506. }
  507. ret = ion_map_iommu(iclient, data->srcp_ihdl,
  508. mdss_get_iommu_domain(domain),
  509. 0, SZ_4K, 0, start, len, 0, 0);
  510. if (ret && (domain == MDSS_IOMMU_DOMAIN_SECURE))
  511. msm_ion_unsecure_buffer(iclient,
  512. data->srcp_ihdl);
  513. data->mapped = true;
  514. } else {
  515. ret = ion_phys(iclient, data->srcp_ihdl, start,
  516. (size_t *) len);
  517. }
  518. if (IS_ERR_VALUE(ret)) {
  519. ion_free(iclient, data->srcp_ihdl);
  520. pr_err("failed to map ion handle (%d)\n", ret);
  521. return ret;
  522. }
  523. }
  524. if (!*start) {
  525. pr_err("start address is zero!\n");
  526. mdss_mdp_put_img(data);
  527. return -ENOMEM;
  528. }
  529. if (!ret && (img->offset < data->len)) {
  530. data->addr += img->offset;
  531. data->len -= img->offset;
  532. pr_debug("mem=%d ihdl=%pK buf=0x%x len=0x%x\n", img->memory_id,
  533. data->srcp_ihdl, data->addr, data->len);
  534. } else {
  535. mdss_mdp_put_img(data);
  536. return ret ? : -EOVERFLOW;
  537. }
  538. return ret;
  539. }
  540. int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase)
  541. {
  542. u32 unit, residue, result;
  543. if (src == 0 || dst == 0)
  544. return -EINVAL;
  545. unit = 1 << PHASE_STEP_SHIFT;
  546. *out_phase = mult_frac(unit, src, dst);
  547. /* check if overflow is possible */
  548. if (src > dst) {
  549. residue = *out_phase - unit;
  550. result = (residue * dst) + residue;
  551. while (result > (unit + (unit >> 1)))
  552. result -= unit;
  553. if ((result > residue) && (result < unit))
  554. return -EOVERFLOW;
  555. }
  556. return 0;
  557. }