static void mdp_dma_schedule(struct msm_fb_data_type *mfd, uint32 term) { /* * dma2 configure VSYNC block * vsync supported on Primary LCD only for now */ int32 mdp_lcd_rd_cnt; uint32 usec_wait_time; uint32 start_y; /* * ToDo: if we can move HRT timer callback to workqueue, we can * move DMA2 power on under mdp_pipe_kickoff(). * This will save a power for hrt time wait. * However if the latency for context switch (hrt irq -> workqueue) * is too big, we will miss the vsync timing. */ if (term == MDP_DMA2_TERM) mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_dma2_update_time_in_usec = MDP_KTIME2USEC(mdp_dma2_last_update_time); if ((!mfd->ibuf.vsync_enable) || (!mfd->panel_info.lcd.vsync_enable) || (mfd->use_mdp_vsync)) { mdp_pipe_kickoff(term, mfd); return; } /* SW vsync logic starts here */ /* get current rd counter */ mdp_lcd_rd_cnt = mdp_get_lcd_line_counter(mfd); if (mdp_dma2_update_time_in_usec != 0) { uint32 num, den; /* * roi width boundary calculation to know the size of pixel * width that MDP can send faster or slower than LCD read * pointer */ num = mdp_last_dma2_update_width * mdp_last_dma2_update_height; den = (((mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) / 1000) * (mdp_dma2_update_time_in_usec / 100)) / 1000; if (den == 0) mfd->vsync_width_boundary[mdp_last_dma2_update_width] = mfd->panel_info.xres + 1; else mfd->vsync_width_boundary[mdp_last_dma2_update_width] = (int)(num / den); } if (mfd->vsync_width_boundary[mdp_last_dma2_update_width] > mdp_curr_dma2_update_width) { /* MDP wrp is faster than LCD rdp */ mdp_lcd_rd_cnt += mdp_lcd_rd_cnt_offset_fast; } else { /* MDP wrp is slower than LCD rdp */ mdp_lcd_rd_cnt -= mdp_lcd_rd_cnt_offset_slow; } if (mdp_lcd_rd_cnt < 0) mdp_lcd_rd_cnt = mfd->total_lcd_lines + mdp_lcd_rd_cnt; else if (mdp_lcd_rd_cnt > mfd->total_lcd_lines) mdp_lcd_rd_cnt = mdp_lcd_rd_cnt - mfd->total_lcd_lines - 1; /* get wrt pointer position */ start_y = mfd->ibuf.dma_y; /* measure line difference between start_y and rd counter */ if (start_y > mdp_lcd_rd_cnt) { /* * *100 for lcd_ref_hzx100 was already multiplied by 100 * *1000000 is for usec conversion */ if ((start_y - mdp_lcd_rd_cnt) <= mdp_vsync_usec_wait_line_too_short) usec_wait_time = 0; else usec_wait_time = ((start_y - mdp_lcd_rd_cnt) * 1000000) / ((mfd->total_lcd_lines * mfd->panel_info.lcd.refx100) / 100); } else { if ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) <= mdp_vsync_usec_wait_line_too_short) usec_wait_time = 0; else usec_wait_time = ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) * 1000000) / ((mfd->total_lcd_lines * mfd->panel_info.lcd.refx100) / 100); } mdp_last_dma2_update_width = mdp_curr_dma2_update_width; mdp_last_dma2_update_height = mdp_curr_dma2_update_height; if (usec_wait_time == 0) { mdp_pipe_kickoff(term, mfd); } else { ktime_t wait_time; wait_time.tv.sec = 0; wait_time.tv.nsec = usec_wait_time * 1000; if (msm_fb_debug_enabled) { vt = ktime_get_real(); mdp_expected_usec_wait = usec_wait_time; } hrtimer_start(&mfd->dma_hrtimer, wait_time, HRTIMER_MODE_REL); } }
static void mdp_dma_schedule(struct msm_fb_data_type *mfd, uint32 term) { int32 mdp_lcd_rd_cnt; uint32 usec_wait_time; uint32 start_y; if (term == MDP_DMA2_TERM) mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); mdp_dma2_update_time_in_usec = MDP_KTIME2USEC(mdp_dma2_last_update_time); if ((!mfd->ibuf.vsync_enable) || (!mfd->panel_info.lcd.vsync_enable) || (mfd->use_mdp_vsync)) { mdp_pipe_kickoff(term, mfd); return; } mdp_lcd_rd_cnt = mdp_get_lcd_line_counter(mfd); if (mdp_dma2_update_time_in_usec != 0) { uint32 num, den; num = mdp_last_dma2_update_width * mdp_last_dma2_update_height; den = (((mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) / 1000) * (mdp_dma2_update_time_in_usec / 100)) / 1000; if (den == 0) mfd->vsync_width_boundary[mdp_last_dma2_update_width] = mfd->panel_info.xres + 1; else mfd->vsync_width_boundary[mdp_last_dma2_update_width] = (int)(num / den); } if (mfd->vsync_width_boundary[mdp_last_dma2_update_width] > mdp_curr_dma2_update_width) { mdp_lcd_rd_cnt += mdp_lcd_rd_cnt_offset_fast; } else { mdp_lcd_rd_cnt -= mdp_lcd_rd_cnt_offset_slow; } if (mdp_lcd_rd_cnt < 0) mdp_lcd_rd_cnt = mfd->total_lcd_lines + mdp_lcd_rd_cnt; else if (mdp_lcd_rd_cnt > mfd->total_lcd_lines) mdp_lcd_rd_cnt = mdp_lcd_rd_cnt - mfd->total_lcd_lines - 1; start_y = mfd->ibuf.dma_y; if (start_y > mdp_lcd_rd_cnt) { if ((start_y - mdp_lcd_rd_cnt) <= mdp_vsync_usec_wait_line_too_short) usec_wait_time = 0; else usec_wait_time = ((start_y - mdp_lcd_rd_cnt) * 1000000) / ((mfd->total_lcd_lines * mfd->panel_info.lcd.refx100) / 100); } else { if ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) <= mdp_vsync_usec_wait_line_too_short) usec_wait_time = 0; else usec_wait_time = ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) * 1000000) / ((mfd->total_lcd_lines * mfd->panel_info.lcd.refx100) / 100); } mdp_last_dma2_update_width = mdp_curr_dma2_update_width; mdp_last_dma2_update_height = mdp_curr_dma2_update_height; if (usec_wait_time == 0) { mdp_pipe_kickoff(term, mfd); } else { ktime_t wait_time; wait_time.tv.sec = 0; wait_time.tv.nsec = usec_wait_time * 1000; if (msm_fb_debug_enabled) { vt = ktime_get_real(); mdp_expected_usec_wait = usec_wait_time; } hrtimer_start(&mfd->dma_hrtimer, wait_time, HRTIMER_MODE_REL); } }