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