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