mdp_dma.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /* Copyright (c) 2008-2012, 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. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/sched.h>
  16. #include <linux/time.h>
  17. #include <linux/init.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/hrtimer.h>
  20. #include <mach/hardware.h>
  21. #include <linux/io.h>
  22. #include <asm/system.h>
  23. #include <asm/mach-types.h>
  24. #include <linux/semaphore.h>
  25. #include <linux/spinlock.h>
  26. #include <linux/fb.h>
  27. #include "mdp.h"
  28. #include "msm_fb.h"
  29. #include "mddihost.h"
  30. static uint32 mdp_last_dma2_update_width;
  31. static uint32 mdp_last_dma2_update_height;
  32. static uint32 mdp_curr_dma2_update_width;
  33. static uint32 mdp_curr_dma2_update_height;
  34. ktime_t mdp_dma2_last_update_time = { 0 };
  35. int mdp_lcd_rd_cnt_offset_slow = 20;
  36. int mdp_lcd_rd_cnt_offset_fast = 20;
  37. int mdp_vsync_usec_wait_line_too_short = 5;
  38. uint32 mdp_dma2_update_time_in_usec;
  39. uint32 mdp_total_vdopkts;
  40. extern u32 msm_fb_debug_enabled;
  41. extern struct workqueue_struct *mdp_dma_wq;
  42. int vsync_start_y_adjust = 4;
  43. static void mdp_dma2_update_lcd(struct msm_fb_data_type *mfd)
  44. {
  45. MDPIBUF *iBuf = &mfd->ibuf;
  46. int mddi_dest = FALSE;
  47. int cmd_mode = FALSE;
  48. uint32 outBpp = iBuf->bpp;
  49. uint32 dma2_cfg_reg;
  50. uint8 *src;
  51. uint32 mddi_ld_param;
  52. uint16 mddi_vdo_packet_reg;
  53. #ifndef CONFIG_FB_MSM_MDP303
  54. struct msm_fb_panel_data *pdata =
  55. (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
  56. #endif
  57. uint32 ystride = mfd->fbi->fix.line_length;
  58. uint32 mddi_pkt_desc;
  59. dma2_cfg_reg = DMA_PACK_ALIGN_LSB |
  60. DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS;
  61. #ifdef CONFIG_FB_MSM_MDP22
  62. dma2_cfg_reg |= DMA_PACK_TIGHT;
  63. #endif
  64. #ifdef CONFIG_FB_MSM_MDP30
  65. /*
  66. * Software workaround: On 7x25/7x27, the MDP will not
  67. * respond if dma_w is 1 pixel. Set the update width to
  68. * 2 pixels and adjust the x offset if needed.
  69. */
  70. if (iBuf->dma_w == 1) {
  71. iBuf->dma_w = 2;
  72. if (iBuf->dma_x == (iBuf->ibuf_width - 2))
  73. iBuf->dma_x--;
  74. }
  75. #endif
  76. if (mfd->fb_imgType == MDP_BGR_565)
  77. dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
  78. else if (mfd->fb_imgType == MDP_RGBA_8888)
  79. dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
  80. else
  81. dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
  82. if (outBpp == 4) {
  83. dma2_cfg_reg |= DMA_IBUF_C3ALPHA_EN;
  84. dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888;
  85. }
  86. if (outBpp == 2)
  87. dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
  88. mddi_ld_param = 0;
  89. mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
  90. if ((mfd->panel_info.type == MDDI_PANEL) ||
  91. (mfd->panel_info.type == EXT_MDDI_PANEL)) {
  92. dma2_cfg_reg |= DMA_OUT_SEL_MDDI;
  93. mddi_dest = TRUE;
  94. if (mfd->panel_info.type == MDDI_PANEL) {
  95. mdp_total_vdopkts++;
  96. if (mfd->panel_info.pdest == DISPLAY_1) {
  97. dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY;
  98. mddi_ld_param = 0;
  99. #ifdef MDDI_HOST_WINDOW_WORKAROUND
  100. mddi_window_adjust(mfd, iBuf->dma_x,
  101. iBuf->dma_w - 1, iBuf->dma_y,
  102. iBuf->dma_h - 1);
  103. #endif
  104. } else {
  105. dma2_cfg_reg |=
  106. DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY;
  107. mddi_ld_param = 1;
  108. #ifdef MDDI_HOST_WINDOW_WORKAROUND
  109. mddi_window_adjust(mfd, iBuf->dma_x,
  110. iBuf->dma_w - 1, iBuf->dma_y,
  111. iBuf->dma_h - 1);
  112. #endif
  113. }
  114. } else {
  115. dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL;
  116. mddi_ld_param = 2;
  117. }
  118. #ifdef CONFIG_FB_MSM_MDP303
  119. } else if (mfd->panel_info.type == MIPI_CMD_PANEL) {
  120. cmd_mode = TRUE;
  121. dma2_cfg_reg |= DMA_OUT_SEL_DSI_CMD;
  122. #endif
  123. } else {
  124. if (mfd->panel_info.pdest == DISPLAY_1) {
  125. dma2_cfg_reg |= DMA_AHBM_LCD_SEL_PRIMARY;
  126. outp32(MDP_EBI2_LCD0, mfd->data_port_phys);
  127. } else {
  128. dma2_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY;
  129. outp32(MDP_EBI2_LCD1, mfd->data_port_phys);
  130. }
  131. }
  132. src = (uint8 *) iBuf->buf;
  133. /* starting input address */
  134. src += iBuf->dma_x * outBpp + iBuf->dma_y * ystride;
  135. mdp_curr_dma2_update_width = iBuf->dma_w;
  136. mdp_curr_dma2_update_height = iBuf->dma_h;
  137. /* MDP cmd block enable */
  138. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
  139. #ifdef CONFIG_FB_MSM_MDP22
  140. MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0184,
  141. (iBuf->dma_h << 16 | iBuf->dma_w));
  142. MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0188, src);
  143. MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x018C, ystride);
  144. #else
  145. if (cmd_mode)
  146. MDP_OUTP(MDP_BASE + 0x90004,
  147. (mfd->panel_info.yres << 16 | mfd->panel_info.xres));
  148. else
  149. MDP_OUTP(MDP_BASE + 0x90004, (iBuf->dma_h << 16 | iBuf->dma_w));
  150. MDP_OUTP(MDP_BASE + 0x90008, src);
  151. MDP_OUTP(MDP_BASE + 0x9000c, ystride);
  152. #endif
  153. if (mfd->panel_info.bpp == 18) {
  154. mddi_pkt_desc = MDDI_VDO_PACKET_DESC;
  155. dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
  156. DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
  157. } else if (mfd->panel_info.bpp == 24) {
  158. mddi_pkt_desc = MDDI_VDO_PACKET_DESC_24;
  159. dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 24BPP */
  160. DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
  161. } else {
  162. mddi_pkt_desc = MDDI_VDO_PACKET_DESC_16;
  163. dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
  164. DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
  165. }
  166. #ifndef CONFIG_FB_MSM_MDP303
  167. if (mddi_dest) {
  168. #ifdef CONFIG_FB_MSM_MDP22
  169. MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0194,
  170. (iBuf->dma_y << 16) | iBuf->dma_x);
  171. MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0, mddi_ld_param);
  172. MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4,
  173. (mddi_pkt_desc << 16) | mddi_vdo_packet_reg);
  174. #else
  175. MDP_OUTP(MDP_BASE + 0x90010, (iBuf->dma_y << 16) | iBuf->dma_x);
  176. MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
  177. MDP_OUTP(MDP_BASE + 0x00094,
  178. (mddi_pkt_desc << 16) | mddi_vdo_packet_reg);
  179. #endif
  180. } else {
  181. /* setting EBI2 LCDC write window */
  182. pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
  183. iBuf->dma_h);
  184. }
  185. #else
  186. if (mfd->panel_info.type == MIPI_CMD_PANEL) {
  187. /* dma_p = 0, dma_s = 1 */
  188. MDP_OUTP(MDP_BASE + 0xF1000, 0x10);
  189. /* enable dsi trigger on dma_p */
  190. MDP_OUTP(MDP_BASE + 0xF1004, 0x01);
  191. }
  192. #endif
  193. /* dma2 config register */
  194. #ifdef MDP_HW_VSYNC
  195. MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
  196. if ((mfd->use_mdp_vsync) &&
  197. (mfd->ibuf.vsync_enable) && (mfd->panel_info.lcd.vsync_enable)) {
  198. uint32 start_y;
  199. if (vsync_start_y_adjust <= iBuf->dma_y)
  200. start_y = iBuf->dma_y - vsync_start_y_adjust;
  201. else
  202. start_y =
  203. (mfd->total_lcd_lines - 1) - (vsync_start_y_adjust -
  204. iBuf->dma_y);
  205. /*
  206. * MDP VSYNC clock must be On by now so, we don't have to
  207. * re-enable it
  208. */
  209. MDP_OUTP(MDP_BASE + 0x210, start_y);
  210. MDP_OUTP(MDP_BASE + 0x20c, 1); /* enable prim vsync */
  211. } else {
  212. MDP_OUTP(MDP_BASE + 0x20c, 0); /* disable prim vsync */
  213. }
  214. #else
  215. #ifdef CONFIG_FB_MSM_MDP22
  216. MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0180, dma2_cfg_reg);
  217. #else
  218. MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
  219. #endif
  220. #endif /* MDP_HW_VSYNC */
  221. /* MDP cmd block disable */
  222. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
  223. }
  224. static ktime_t vt = { 0 };
  225. int mdp_usec_diff_threshold = 100;
  226. int mdp_expected_usec_wait;
  227. enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht)
  228. {
  229. struct msm_fb_data_type *mfd = NULL;
  230. mfd = container_of(ht, struct msm_fb_data_type, dma_hrtimer);
  231. mdp_pipe_kickoff(MDP_DMA2_TERM, mfd);
  232. if (msm_fb_debug_enabled) {
  233. ktime_t t;
  234. int usec_diff;
  235. int actual_wait;
  236. t = ktime_get_real();
  237. actual_wait = ktime_to_us(ktime_sub(t, vt));
  238. usec_diff = actual_wait - mdp_expected_usec_wait;
  239. if ((mdp_usec_diff_threshold < usec_diff) || (usec_diff < 0))
  240. MSM_FB_DEBUG
  241. ("HRT Diff = %d usec Exp=%d usec Act=%d usec\n",
  242. usec_diff, mdp_expected_usec_wait, actual_wait);
  243. }
  244. return HRTIMER_NORESTART;
  245. }
  246. #ifdef CONFIG_FB_MSM_MDP303
  247. static int busy_wait_cnt;
  248. void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
  249. {
  250. unsigned long flag;
  251. int need_wait = 0;
  252. #ifdef DSI_CLK_CTRL
  253. mod_timer(&dsi_clock_timer, jiffies + HZ); /* one second */
  254. #endif
  255. spin_lock_irqsave(&mdp_spin_lock, flag);
  256. #ifdef DSI_CLK_CTRL
  257. spin_lock_bh(&dsi_clk_lock);
  258. if (mipi_dsi_clk_on == 0)
  259. mipi_dsi_turn_on_clks();
  260. spin_unlock_bh(&dsi_clk_lock);
  261. #endif
  262. if (mfd->dma->busy == TRUE) {
  263. if (busy_wait_cnt == 0)
  264. INIT_COMPLETION(mfd->dma->comp);
  265. busy_wait_cnt++;
  266. need_wait++;
  267. }
  268. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  269. if (need_wait) {
  270. /* wait until DMA finishes the current job */
  271. wait_for_completion(&mfd->dma->comp);
  272. }
  273. }
  274. #endif
  275. static void mdp_dma_schedule(struct msm_fb_data_type *mfd, uint32 term)
  276. {
  277. /*
  278. * dma2 configure VSYNC block
  279. * vsync supported on Primary LCD only for now
  280. */
  281. int32 mdp_lcd_rd_cnt;
  282. uint32 usec_wait_time;
  283. uint32 start_y;
  284. /*
  285. * ToDo: if we can move HRT timer callback to workqueue, we can
  286. * move DMA2 power on under mdp_pipe_kickoff().
  287. * This will save a power for hrt time wait.
  288. * However if the latency for context switch (hrt irq -> workqueue)
  289. * is too big, we will miss the vsync timing.
  290. */
  291. if (term == MDP_DMA2_TERM)
  292. mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
  293. mdp_dma2_update_time_in_usec = ktime_to_us(mdp_dma2_last_update_time);
  294. if ((!mfd->ibuf.vsync_enable) || (!mfd->panel_info.lcd.vsync_enable)
  295. || (mfd->use_mdp_vsync)) {
  296. mdp_pipe_kickoff(term, mfd);
  297. return;
  298. }
  299. /* SW vsync logic starts here */
  300. /* get current rd counter */
  301. mdp_lcd_rd_cnt = mdp_get_lcd_line_counter(mfd);
  302. if (mdp_dma2_update_time_in_usec != 0) {
  303. uint32 num, den;
  304. /*
  305. * roi width boundary calculation to know the size of pixel
  306. * width that MDP can send faster or slower than LCD read
  307. * pointer
  308. */
  309. num = mdp_last_dma2_update_width * mdp_last_dma2_update_height;
  310. den =
  311. (((mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) /
  312. 1000) * (mdp_dma2_update_time_in_usec / 100)) / 1000;
  313. if (den == 0)
  314. mfd->vsync_width_boundary[mdp_last_dma2_update_width] =
  315. mfd->panel_info.xres + 1;
  316. else
  317. mfd->vsync_width_boundary[mdp_last_dma2_update_width] =
  318. (int)(num / den);
  319. }
  320. if (mfd->vsync_width_boundary[mdp_last_dma2_update_width] >
  321. mdp_curr_dma2_update_width) {
  322. /* MDP wrp is faster than LCD rdp */
  323. mdp_lcd_rd_cnt += mdp_lcd_rd_cnt_offset_fast;
  324. } else {
  325. /* MDP wrp is slower than LCD rdp */
  326. mdp_lcd_rd_cnt -= mdp_lcd_rd_cnt_offset_slow;
  327. }
  328. if (mdp_lcd_rd_cnt < 0)
  329. mdp_lcd_rd_cnt = mfd->total_lcd_lines + mdp_lcd_rd_cnt;
  330. else if (mdp_lcd_rd_cnt > mfd->total_lcd_lines)
  331. mdp_lcd_rd_cnt = mdp_lcd_rd_cnt - mfd->total_lcd_lines - 1;
  332. /* get wrt pointer position */
  333. start_y = mfd->ibuf.dma_y;
  334. /* measure line difference between start_y and rd counter */
  335. if (start_y > mdp_lcd_rd_cnt) {
  336. /*
  337. * *100 for lcd_ref_hzx100 was already multiplied by 100
  338. * *1000000 is for usec conversion
  339. */
  340. if ((start_y - mdp_lcd_rd_cnt) <=
  341. mdp_vsync_usec_wait_line_too_short)
  342. usec_wait_time = 0;
  343. else
  344. usec_wait_time =
  345. ((start_y -
  346. mdp_lcd_rd_cnt) * 1000000) /
  347. ((mfd->total_lcd_lines *
  348. mfd->panel_info.lcd.refx100) / 100);
  349. } else {
  350. if ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) <=
  351. mdp_vsync_usec_wait_line_too_short)
  352. usec_wait_time = 0;
  353. else
  354. usec_wait_time =
  355. ((start_y +
  356. (mfd->total_lcd_lines -
  357. mdp_lcd_rd_cnt)) * 1000000) /
  358. ((mfd->total_lcd_lines *
  359. mfd->panel_info.lcd.refx100) / 100);
  360. }
  361. mdp_last_dma2_update_width = mdp_curr_dma2_update_width;
  362. mdp_last_dma2_update_height = mdp_curr_dma2_update_height;
  363. if (usec_wait_time == 0) {
  364. mdp_pipe_kickoff(term, mfd);
  365. } else {
  366. ktime_t wait_time;
  367. wait_time = ns_to_ktime(usec_wait_time * 1000);
  368. if (msm_fb_debug_enabled) {
  369. vt = ktime_get_real();
  370. mdp_expected_usec_wait = usec_wait_time;
  371. }
  372. hrtimer_start(&mfd->dma_hrtimer, wait_time, HRTIMER_MODE_REL);
  373. }
  374. }
  375. #ifdef MDDI_HOST_WINDOW_WORKAROUND
  376. static void mdp_dma2_update_sub(struct msm_fb_data_type *mfd);
  377. void mdp_dma2_update(struct msm_fb_data_type *mfd)
  378. {
  379. MDPIBUF *iBuf;
  380. uint32 upper_height;
  381. if (mfd->panel.type == EXT_MDDI_PANEL) {
  382. mdp_dma2_update_sub(mfd);
  383. return;
  384. }
  385. iBuf = &mfd->ibuf;
  386. upper_height =
  387. (uint32) mddi_assign_pkt_height((uint16) iBuf->dma_w,
  388. (uint16) iBuf->dma_h, 18);
  389. if (upper_height >= iBuf->dma_h) {
  390. mdp_dma2_update_sub(mfd);
  391. } else {
  392. uint32 lower_height;
  393. /* sending the upper region first */
  394. lower_height = iBuf->dma_h - upper_height;
  395. iBuf->dma_h = upper_height;
  396. mdp_dma2_update_sub(mfd);
  397. /* sending the lower region second */
  398. iBuf->dma_h = lower_height;
  399. iBuf->dma_y += lower_height;
  400. iBuf->vsync_enable = FALSE;
  401. mdp_dma2_update_sub(mfd);
  402. }
  403. }
  404. static void mdp_dma2_update_sub(struct msm_fb_data_type *mfd)
  405. #else
  406. void mdp_dma2_update(struct msm_fb_data_type *mfd)
  407. #endif
  408. {
  409. unsigned long flag;
  410. static int first_vsync;
  411. int need_wait = 0;
  412. down(&mfd->dma->mutex);
  413. if ((mfd) && (mfd->panel_power_on)) {
  414. down(&mfd->sem);
  415. spin_lock_irqsave(&mdp_spin_lock, flag);
  416. if (mfd->dma->busy == TRUE)
  417. need_wait++;
  418. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  419. if (need_wait)
  420. wait_for_completion_killable(&mfd->dma->comp);
  421. /* schedule DMA to start */
  422. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
  423. mfd->ibuf_flushed = TRUE;
  424. mdp_dma2_update_lcd(mfd);
  425. spin_lock_irqsave(&mdp_spin_lock, flag);
  426. mdp_enable_irq(MDP_DMA2_TERM);
  427. mfd->dma->busy = TRUE;
  428. INIT_COMPLETION(mfd->dma->comp);
  429. INIT_COMPLETION(vsync_cntrl.vsync_comp);
  430. if (!vsync_cntrl.vsync_irq_enabled &&
  431. vsync_cntrl.disabled_clocks) {
  432. MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
  433. outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
  434. mdp_intr_mask |= MDP_PRIM_RDPTR;
  435. outp32(MDP_INTR_ENABLE, mdp_intr_mask);
  436. mdp_enable_irq(MDP_VSYNC_TERM);
  437. vsync_cntrl.vsync_dma_enabled = 1;
  438. }
  439. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  440. /* schedule DMA to start */
  441. mdp_dma_schedule(mfd, MDP_DMA2_TERM);
  442. up(&mfd->sem);
  443. /* wait until Vsync finishes the current job */
  444. if (first_vsync) {
  445. if (!wait_for_completion_killable_timeout
  446. (&vsync_cntrl.vsync_comp, HZ/10))
  447. pr_err("Timedout DMA %s %d", __func__,
  448. __LINE__);
  449. } else {
  450. first_vsync = 1;
  451. }
  452. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
  453. /* signal if pan function is waiting for the update completion */
  454. if (mfd->pan_waiting) {
  455. mfd->pan_waiting = FALSE;
  456. complete(&mfd->pan_comp);
  457. }
  458. }
  459. up(&mfd->dma->mutex);
  460. }
  461. void mdp_dma_vsync_ctrl(int enable)
  462. {
  463. unsigned long flag;
  464. int disabled_clocks;
  465. if (vsync_cntrl.vsync_irq_enabled == enable)
  466. return;
  467. spin_lock_irqsave(&mdp_spin_lock, flag);
  468. if (!enable)
  469. INIT_COMPLETION(vsync_cntrl.vsync_wait);
  470. vsync_cntrl.vsync_irq_enabled = enable;
  471. disabled_clocks = vsync_cntrl.disabled_clocks;
  472. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  473. if (enable && disabled_clocks)
  474. mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
  475. spin_lock_irqsave(&mdp_spin_lock, flag);
  476. if (enable && vsync_cntrl.disabled_clocks &&
  477. !vsync_cntrl.vsync_dma_enabled) {
  478. MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
  479. outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
  480. mdp_intr_mask |= MDP_PRIM_RDPTR;
  481. outp32(MDP_INTR_ENABLE, mdp_intr_mask);
  482. mdp_enable_irq(MDP_VSYNC_TERM);
  483. vsync_cntrl.disabled_clocks = 0;
  484. } else if (enable && vsync_cntrl.disabled_clocks) {
  485. vsync_cntrl.disabled_clocks = 0;
  486. }
  487. spin_unlock_irqrestore(&mdp_spin_lock, flag);
  488. if (vsync_cntrl.vsync_irq_enabled &&
  489. atomic_read(&vsync_cntrl.suspend) == 0)
  490. atomic_set(&vsync_cntrl.vsync_resume, 1);
  491. }
  492. void mdp_lcd_update_workqueue_handler(struct work_struct *work)
  493. {
  494. struct msm_fb_data_type *mfd = NULL;
  495. mfd = container_of(work, struct msm_fb_data_type, dma_update_worker);
  496. if (mfd)
  497. mfd->dma_fnc(mfd);
  498. }
  499. void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
  500. boolean sync)
  501. {
  502. struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
  503. struct fb_info *fbi = mfd->fbi;
  504. MDPIBUF *iBuf;
  505. int bpp = info->var.bits_per_pixel / 8;
  506. down(&mfd->sem);
  507. iBuf = &mfd->ibuf;
  508. if (mfd->display_iova)
  509. iBuf->buf = (uint8 *)mfd->display_iova;
  510. else
  511. iBuf->buf = (uint8 *) info->fix.smem_start;
  512. iBuf->buf += calc_fb_offset(mfd, fbi, bpp);
  513. iBuf->ibuf_width = info->var.xres_virtual;
  514. iBuf->bpp = bpp;
  515. iBuf->vsync_enable = sync;
  516. if (dirty) {
  517. /*
  518. * ToDo: dirty region check inside var.xoffset+xres
  519. * <-> var.yoffset+yres
  520. */
  521. iBuf->dma_x = dirty->xoffset % info->var.xres;
  522. iBuf->dma_y = dirty->yoffset % info->var.yres;
  523. iBuf->dma_w = dirty->width;
  524. iBuf->dma_h = dirty->height;
  525. } else {
  526. iBuf->dma_x = 0;
  527. iBuf->dma_y = 0;
  528. iBuf->dma_w = info->var.xres;
  529. iBuf->dma_h = info->var.yres;
  530. }
  531. mfd->ibuf_flushed = FALSE;
  532. up(&mfd->sem);
  533. }
  534. void mdp_dma_pan_update(struct fb_info *info)
  535. {
  536. struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
  537. MDPIBUF *iBuf;
  538. iBuf = &mfd->ibuf;
  539. if (mfd->sw_currently_refreshing) {
  540. /* we need to wait for the pending update */
  541. mfd->pan_waiting = TRUE;
  542. if (!mfd->ibuf_flushed) {
  543. wait_for_completion_killable(&mfd->pan_comp);
  544. }
  545. /* waiting for this update to complete */
  546. mfd->pan_waiting = TRUE;
  547. wait_for_completion_killable(&mfd->pan_comp);
  548. } else
  549. mfd->dma_fnc(mfd);
  550. }
  551. void mdp_refresh_screen(unsigned long data)
  552. {
  553. struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
  554. if ((mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) {
  555. init_timer(&mfd->refresh_timer);
  556. mfd->refresh_timer.function = mdp_refresh_screen;
  557. mfd->refresh_timer.data = data;
  558. if (mfd->dma->busy)
  559. /* come back in 1 msec */
  560. mfd->refresh_timer.expires = jiffies + (HZ / 1000);
  561. else
  562. mfd->refresh_timer.expires =
  563. jiffies + mfd->refresh_timer_duration;
  564. add_timer(&mfd->refresh_timer);
  565. if (!mfd->dma->busy) {
  566. if (!queue_work(mdp_dma_wq, &mfd->dma_update_worker)) {
  567. MSM_FB_DEBUG("mdp_dma: can't queue_work! -> \
  568. MDP/MDDI/LCD clock speed needs to be increased\n");
  569. }
  570. }
  571. } else {
  572. if (!mfd->hw_refresh)
  573. complete(&mfd->refresher_comp);
  574. }
  575. }