gma500: udelay(20000) it too long again
[pandora-kernel.git] / drivers / staging / gma500 / mdfld_dsi_dbi_dpu.c
1 /*
2  * Copyright © 2010-2011 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  * Jim Liu <jim.liu@intel.com>
25  * Jackie Li<yaodong.li@intel.com>
26  */
27
28 #include "mdfld_dsi_dbi_dpu.h"
29 #include "mdfld_dsi_dbi.h"
30
31 /*
32  * NOTE: all mdlfd_x_damage funcs should be called by holding dpu_update_lock
33  */
34
35 static int mdfld_cursor_damage(struct mdfld_dbi_dpu_info *dpu_info,
36                            mdfld_plane_t plane,
37                            struct psb_drm_dpu_rect *damaged_rect)
38 {
39         int x, y;
40         int new_x, new_y;
41         struct psb_drm_dpu_rect *rect;
42         struct psb_drm_dpu_rect *pipe_rect;
43         int cursor_size;
44         struct mdfld_cursor_info *cursor;
45         mdfld_plane_t fb_plane;
46
47         if (plane == MDFLD_CURSORA) {
48                 cursor = &dpu_info->cursors[0];
49                 x = dpu_info->cursors[0].x;
50                 y = dpu_info->cursors[0].y;
51                 cursor_size = dpu_info->cursors[0].size;
52                 pipe_rect = &dpu_info->damage_pipea;
53                 fb_plane = MDFLD_PLANEA;
54         } else {
55                 cursor = &dpu_info->cursors[1];
56                 x = dpu_info->cursors[1].x;
57                 y = dpu_info->cursors[1].y;
58                 cursor_size = dpu_info->cursors[1].size;
59                 pipe_rect = &dpu_info->damage_pipec;
60                 fb_plane = MDFLD_PLANEC;
61         }
62         new_x = damaged_rect->x;
63         new_y = damaged_rect->y;
64
65         if (x == new_x && y == new_y)
66                 return 0;
67
68         rect = &dpu_info->damaged_rects[plane];
69         /* Move to right */
70         if (new_x >= x) {
71                 if (new_y > y) {
72                         rect->x = x;
73                         rect->y = y;
74                         rect->width = (new_x + cursor_size) - x;
75                         rect->height = (new_y + cursor_size) - y;
76                         goto cursor_out;
77                 } else {
78                         rect->x = x;
79                         rect->y = new_y;
80                         rect->width = (new_x + cursor_size) - x;
81                         rect->height = (y - new_y);
82                         goto cursor_out;
83                 }
84         } else {
85                 if (new_y > y) {
86                         rect->x = new_x;
87                         rect->y = y;
88                         rect->width = (x + cursor_size) - new_x;
89                         rect->height = new_y - y;
90                         goto cursor_out;
91                 } else {
92                         rect->x = new_x;
93                         rect->y = new_y;
94                         rect->width = (x + cursor_size) - new_x;
95                         rect->height = (y + cursor_size) - new_y;
96                 }
97         }
98 cursor_out:
99         if (new_x < 0)
100                 cursor->x = 0;
101         else if (new_x > 864)
102                 cursor->x = 864;
103         else
104                 cursor->x = new_x;
105
106         if (new_y < 0)
107                 cursor->y = 0;
108         else if (new_y > 480)
109                 cursor->y = 480;
110         else
111                 cursor->y = new_y;
112
113         /*
114          * FIXME: this is a workaround for cursor plane update,
115          * remove it later!
116          */
117         rect->x = 0;
118         rect->y = 0;
119         rect->width = 864;
120         rect->height = 480;
121
122         mdfld_check_boundary(dpu_info, rect);
123         mdfld_dpu_region_extent(pipe_rect, rect);
124
125         /* Update pending status of dpu_info */
126         dpu_info->pending |= (1 << plane);
127         /* Update fb panel as well */
128         dpu_info->pending |= (1 << fb_plane);
129         return 0;
130 }
131
132 static int mdfld_fb_damage(struct mdfld_dbi_dpu_info *dpu_info,
133                                    mdfld_plane_t plane,
134                                    struct psb_drm_dpu_rect *damaged_rect)
135 {
136         struct psb_drm_dpu_rect *rect;
137
138         if (plane == MDFLD_PLANEA)
139                 rect = &dpu_info->damage_pipea;
140         else
141                 rect = &dpu_info->damage_pipec;
142
143         mdfld_check_boundary(dpu_info, damaged_rect);
144
145         /* Add fb damage area to this pipe */
146         mdfld_dpu_region_extent(rect, damaged_rect);
147
148         /* Update pending status of dpu_info */
149         dpu_info->pending |= (1 << plane);
150         return 0;
151 }
152
153 /* Do nothing here, right now */
154 static int mdfld_overlay_damage(struct mdfld_dbi_dpu_info *dpu_info,
155                                 mdfld_plane_t plane,
156                                 struct psb_drm_dpu_rect *damaged_rect)
157 {
158         return 0;
159 }
160
161 int mdfld_dbi_dpu_report_damage(struct drm_device *dev,
162                                 mdfld_plane_t plane,
163                                 struct psb_drm_dpu_rect *rect)
164 {
165         struct drm_psb_private *dev_priv = dev->dev_private;
166         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
167         int ret = 0;
168
169         /* DPU not in use, no damage reporting needed */
170         if (dpu_info == NULL)
171                 return 0;
172
173         spin_lock(&dpu_info->dpu_update_lock);
174
175         switch (plane) {
176         case MDFLD_PLANEA:
177         case MDFLD_PLANEC:
178                 mdfld_fb_damage(dpu_info, plane, rect);
179                 break;
180         case MDFLD_CURSORA:
181         case MDFLD_CURSORC:
182                 mdfld_cursor_damage(dpu_info, plane, rect);
183                 break;
184         case MDFLD_OVERLAYA:
185         case MDFLD_OVERLAYC:
186                 mdfld_overlay_damage(dpu_info, plane, rect);
187                 break;
188         default:
189                 DRM_ERROR("Invalid plane type %d\n", plane);
190                 ret = -EINVAL;
191         }
192         spin_unlock(&dpu_info->dpu_update_lock);
193         return ret;
194 }
195
196 int mdfld_dbi_dpu_report_fullscreen_damage(struct drm_device *dev)
197 {
198         struct drm_psb_private *dev_priv;
199         struct mdfld_dbi_dpu_info *dpu_info;
200         struct mdfld_dsi_config  *dsi_config;
201         struct psb_drm_dpu_rect rect;
202         int i;
203
204         if (!dev) {
205                 DRM_ERROR("Invalid parameter\n");
206                 return -EINVAL;
207         }
208
209         dev_priv = dev->dev_private;
210         dpu_info = dev_priv->dbi_dpu_info;
211
212         /* This is fine - we may be in non DPU mode */
213         if (!dpu_info)
214                 return -EINVAL;
215
216         for (i = 0; i < dpu_info->dbi_output_num; i++) {
217                 dsi_config = dev_priv->dsi_configs[i];
218                 if (dsi_config) {
219                         rect.x = rect.y = 0;
220                         rect.width = dsi_config->fixed_mode->hdisplay;
221                         rect.height = dsi_config->fixed_mode->vdisplay;
222                         mdfld_dbi_dpu_report_damage(dev,
223                                     i ? (MDFLD_PLANEC) : (MDFLD_PLANEA),
224                                     &rect);
225                 }
226         }
227         /* Exit DSR state */
228         mdfld_dpu_exit_dsr(dev);
229         return 0;
230 }
231
232 int mdfld_dsi_dbi_dsr_off(struct drm_device *dev,
233                                         struct psb_drm_dpu_rect *rect)
234 {
235         struct drm_psb_private *dev_priv = dev->dev_private;
236         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
237
238         mdfld_dbi_dpu_report_damage(dev, MDFLD_PLANEA, rect);
239
240         /* If dual display mode */
241         if (dpu_info->dbi_output_num == 2)
242                 mdfld_dbi_dpu_report_damage(dev, MDFLD_PLANEC, rect);
243
244         /* Force dsi to exit DSR mode */
245         mdfld_dpu_exit_dsr(dev);
246         return 0;
247 }
248
249 static void mdfld_dpu_cursor_plane_flush(struct mdfld_dbi_dpu_info *dpu_info,
250                                                  mdfld_plane_t plane)
251 {
252         struct drm_device *dev = dpu_info->dev;
253         u32 curpos_reg = CURAPOS;
254         u32 curbase_reg = CURABASE;
255         u32 curcntr_reg = CURACNTR;
256         struct mdfld_cursor_info *cursor = &dpu_info->cursors[0];
257
258         if (plane == MDFLD_CURSORC) {
259                 curpos_reg = CURCPOS;
260                 curbase_reg = CURCBASE;
261                 curcntr_reg = CURCCNTR;
262                 cursor = &dpu_info->cursors[1];
263         }
264
265         REG_WRITE(curcntr_reg, REG_READ(curcntr_reg));
266         REG_WRITE(curpos_reg,
267                 (((cursor->x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
268                 ((cursor->y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT)));
269         REG_WRITE(curbase_reg, REG_READ(curbase_reg));
270 }
271
272 static void mdfld_dpu_fb_plane_flush(struct mdfld_dbi_dpu_info *dpu_info,
273                                                  mdfld_plane_t plane)
274 {
275         u32 pipesrc_reg = PIPEASRC;
276         u32 dspsize_reg = DSPASIZE;
277         u32 dspoff_reg = DSPALINOFF;
278         u32 dspsurf_reg = DSPASURF;
279         u32 dspstride_reg = DSPASTRIDE;
280         u32 stride;
281         struct psb_drm_dpu_rect *rect = &dpu_info->damage_pipea;
282         struct drm_device *dev = dpu_info->dev;
283
284         if (plane == MDFLD_PLANEC) {
285                 pipesrc_reg = PIPECSRC;
286                 dspsize_reg = DSPCSIZE;
287                 dspoff_reg = DSPCLINOFF;
288                 dspsurf_reg = DSPCSURF;
289                 dspstride_reg = DSPCSTRIDE;
290                 rect = &dpu_info->damage_pipec;
291         }
292
293         stride = REG_READ(dspstride_reg);
294         /* FIXME: should I do the pipe src update here? */
295         REG_WRITE(pipesrc_reg, ((rect->width - 1) << 16) | (rect->height - 1));
296         /* Flush plane */
297         REG_WRITE(dspsize_reg, ((rect->height - 1) << 16) | (rect->width - 1));
298         REG_WRITE(dspoff_reg, ((rect->x * 4) + (rect->y * stride)));
299         REG_WRITE(dspsurf_reg, REG_READ(dspsurf_reg));
300
301         /*
302          * TODO: wait for flip finished and restore the pipesrc reg,
303          * or cursor will be show at a wrong position
304          */
305 }
306
307 static void mdfld_dpu_overlay_plane_flush(struct mdfld_dbi_dpu_info *dpu_info,
308                                                   mdfld_plane_t plane)
309 {
310 }
311
312 /*
313  * TODO: we are still in dbi normal mode now, we will try to use partial
314  * mode later.
315  */
316 static int mdfld_dbi_prepare_cb(struct mdfld_dsi_dbi_output *dbi_output,
317                                 struct mdfld_dbi_dpu_info *dpu_info, int pipe)
318 {
319         u8 *cb_addr = (u8 *)dbi_output->dbi_cb_addr;
320         u32 *index;
321         struct psb_drm_dpu_rect *rect = pipe ?
322                 (&dpu_info->damage_pipec) : (&dpu_info->damage_pipea);
323
324         /* FIXME: lock command buffer, this may lead to a deadlock,
325            as we already hold the dpu_update_lock */
326         if (!spin_trylock(&dbi_output->cb_lock)) {
327                 DRM_ERROR("lock command buffer failed, try again\n");
328                 return -EAGAIN;
329         }
330
331         index = &dbi_output->cb_write;
332
333         if (*index) {
334                 DRM_ERROR("DBI command buffer unclean\n");
335                 return -EAGAIN;
336         }
337
338         /* Column address */
339         *(cb_addr + ((*index)++)) = set_column_address;
340         *(cb_addr + ((*index)++)) = rect->x >> 8;
341         *(cb_addr + ((*index)++)) = rect->x;
342         *(cb_addr + ((*index)++)) = (rect->x + rect->width - 1) >> 8;
343         *(cb_addr + ((*index)++)) = (rect->x + rect->width - 1);
344
345         *index = 8;
346
347         /* Page address */
348         *(cb_addr + ((*index)++)) = set_page_addr;
349         *(cb_addr + ((*index)++)) = rect->y >> 8;
350         *(cb_addr + ((*index)++)) = rect->y;
351         *(cb_addr + ((*index)++)) = (rect->y + rect->height - 1) >> 8;
352         *(cb_addr + ((*index)++)) = (rect->y + rect->height - 1);
353
354         *index = 16;
355
356         /*write memory*/
357         *(cb_addr + ((*index)++)) = write_mem_start;
358
359         return 0;
360 }
361
362 static int mdfld_dbi_flush_cb(struct mdfld_dsi_dbi_output *dbi_output, int pipe)
363 {
364         u32 cmd_phy = dbi_output->dbi_cb_phy;
365         u32 *index = &dbi_output->cb_write;
366         int reg_offset = pipe ? MIPIC_REG_OFFSET : 0;
367         struct drm_device *dev = dbi_output->dev;
368
369         if (*index == 0 || !dbi_output)
370                 return 0;
371
372         REG_WRITE((MIPIA_CMD_LEN_REG + reg_offset), 0x010505);
373         REG_WRITE((MIPIA_CMD_ADD_REG + reg_offset), cmd_phy | 3);
374
375         *index = 0;
376
377         /* FIXME: unlock command buffer */
378         spin_unlock(&dbi_output->cb_lock);
379         return 0;
380 }
381
382 static int mdfld_dpu_update_pipe(struct mdfld_dsi_dbi_output *dbi_output,
383                                  struct mdfld_dbi_dpu_info *dpu_info, int pipe)
384 {
385         struct drm_device *dev =  dbi_output->dev;
386         struct drm_psb_private *dev_priv = dev->dev_private;
387         mdfld_plane_t cursor_plane = MDFLD_CURSORA;
388         mdfld_plane_t fb_plane = MDFLD_PLANEA;
389         mdfld_plane_t overlay_plane = MDFLD_OVERLAYA;
390         int ret = 0;
391         u32 plane_mask = MDFLD_PIPEA_PLANE_MASK;
392
393         /* Damaged rects on this pipe */
394         if (pipe) {
395                 cursor_plane = MDFLD_CURSORC;
396                 fb_plane = MDFLD_PLANEC;
397                 overlay_plane = MDFLD_OVERLAYC;
398                 plane_mask = MDFLD_PIPEC_PLANE_MASK;
399         }
400
401         /*update cursor which assigned to @pipe*/
402         if (dpu_info->pending & (1 << cursor_plane))
403                 mdfld_dpu_cursor_plane_flush(dpu_info, cursor_plane);
404
405         /*update fb which assigned to @pipe*/
406         if (dpu_info->pending & (1 << fb_plane))
407                 mdfld_dpu_fb_plane_flush(dpu_info, fb_plane);
408
409         /* TODO: update overlay */
410         if (dpu_info->pending & (1 << overlay_plane))
411                 mdfld_dpu_overlay_plane_flush(dpu_info, overlay_plane);
412
413         /* Flush damage area to panel fb */
414         if (dpu_info->pending & plane_mask) {
415                 ret = mdfld_dbi_prepare_cb(dbi_output, dpu_info, pipe);
416                 /*
417                  * TODO: remove b_dsr_enable later,
418                  * added it so that text console could boot smoothly
419                  */
420                 /* Clean pending flags on this pipe */
421                 if (!ret && dev_priv->dsr_enable) {
422                         dpu_info->pending &= ~plane_mask;
423                         /* Reset overlay pipe damage rect */
424                         mdfld_dpu_init_damage(dpu_info, pipe);
425                 }
426         }
427         return ret;
428 }
429
430 static int mdfld_dpu_update_fb(struct drm_device *dev)
431 {
432         struct drm_crtc *crtc;
433         struct psb_intel_crtc *psb_crtc;
434         struct mdfld_dsi_dbi_output **dbi_output;
435         struct drm_psb_private *dev_priv = dev->dev_private;
436         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
437         bool pipe_updated[2];
438         unsigned long irq_flags;
439         u32 dpll_reg = MRST_DPLL_A;
440         u32 dspcntr_reg = DSPACNTR;
441         u32 pipeconf_reg = PIPEACONF;
442         u32 dsplinoff_reg = DSPALINOFF;
443         u32 dspsurf_reg = DSPASURF;
444         u32 mipi_state_reg = MIPIA_INTR_STAT_REG;
445         u32 reg_offset = 0;
446         int pipe;
447         int i;
448         int ret;
449
450         dbi_output = dpu_info->dbi_outputs;
451         pipe_updated[0] = pipe_updated[1] = false;
452
453         if (!gma_power_begin(dev, true))
454                 return -EAGAIN;
455
456         /* Try to prevent any new damage reports */
457         if (!spin_trylock_irqsave(&dpu_info->dpu_update_lock, irq_flags))
458                 return -EAGAIN;
459
460         for (i = 0; i < dpu_info->dbi_output_num; i++) {
461                 crtc = dbi_output[i]->base.base.crtc;
462                 psb_crtc = (crtc) ? to_psb_intel_crtc(crtc) : NULL;
463
464                 pipe = dbi_output[i]->channel_num ? 2 : 0;
465
466                 if (pipe == 2) {
467                         dspcntr_reg = DSPCCNTR;
468                         pipeconf_reg = PIPECCONF;
469                         dsplinoff_reg = DSPCLINOFF;
470                         dspsurf_reg = DSPCSURF;
471                         reg_offset = MIPIC_REG_OFFSET;
472                 }
473
474                 if (!(REG_READ((MIPIA_GEN_FIFO_STAT_REG + reg_offset))
475                                                         & (1 << 27)) ||
476                         !(REG_READ(dpll_reg) & DPLL_VCO_ENABLE) ||
477                         !(REG_READ(dspcntr_reg) & DISPLAY_PLANE_ENABLE) ||
478                         !(REG_READ(pipeconf_reg) & DISPLAY_PLANE_ENABLE)) {
479                         dev_err(dev->dev,
480                                 "DBI FIFO is busy, DSI %d state %x\n",
481                                 pipe,
482                                 REG_READ(mipi_state_reg + reg_offset));
483                         continue;
484                 }
485
486                 /*
487                  *      If DBI output is in a exclusive state then the pipe
488                  *      change won't be updated
489                  */
490                 if (dbi_output[i]->dbi_panel_on &&
491                    !(dbi_output[i]->mode_flags & MODE_SETTING_ON_GOING) &&
492                    !(psb_crtc &&
493                         psb_crtc->mode_flags & MODE_SETTING_ON_GOING) &&
494                    !(dbi_output[i]->mode_flags & MODE_SETTING_IN_DSR)) {
495                         ret = mdfld_dpu_update_pipe(dbi_output[i],
496                                 dpu_info, dbi_output[i]->channel_num ? 2 : 0);
497                         if (!ret)
498                                 pipe_updated[i] = true;
499                 }
500         }
501
502         for (i = 0; i < dpu_info->dbi_output_num; i++)
503                 if (pipe_updated[i])
504                         mdfld_dbi_flush_cb(dbi_output[i],
505                                 dbi_output[i]->channel_num ? 2 : 0);
506
507         spin_unlock_irqrestore(&dpu_info->dpu_update_lock, irq_flags);
508         gma_power_end(dev);
509         return 0;
510 }
511
512 static int __mdfld_dbi_exit_dsr(struct mdfld_dsi_dbi_output *dbi_output,
513                                                                 int pipe)
514 {
515         struct drm_device *dev = dbi_output->dev;
516         struct drm_crtc *crtc = dbi_output->base.base.crtc;
517         struct psb_intel_crtc *psb_crtc = (crtc) ? to_psb_intel_crtc(crtc)
518                                                                 : NULL;
519         u32 reg_val;
520         u32 dpll_reg = MRST_DPLL_A;
521         u32 pipeconf_reg = PIPEACONF;
522         u32 dspcntr_reg = DSPACNTR;
523         u32 dspbase_reg = DSPABASE;
524         u32 dspsurf_reg = DSPASURF;
525         u32 reg_offset = 0;
526
527         if (!dbi_output)
528                 return 0;
529
530         /* If mode setting on-going, back off */
531         if ((dbi_output->mode_flags & MODE_SETTING_ON_GOING) ||
532                 (psb_crtc && psb_crtc->mode_flags & MODE_SETTING_ON_GOING))
533                 return -EAGAIN;
534
535         if (pipe == 2) {
536                 dpll_reg = MRST_DPLL_A;
537                 pipeconf_reg = PIPECCONF;
538                 dspcntr_reg = DSPCCNTR;
539                 dspbase_reg = MDFLD_DSPCBASE;
540                 dspsurf_reg = DSPCSURF;
541
542                 reg_offset = MIPIC_REG_OFFSET;
543         }
544
545         if (!gma_power_begin(dev, true))
546                 return -EAGAIN;
547
548         /* Enable DPLL */
549         reg_val = REG_READ(dpll_reg);
550         if (!(reg_val & DPLL_VCO_ENABLE)) {
551
552                 if (reg_val & MDFLD_PWR_GATE_EN) {
553                         reg_val &= ~MDFLD_PWR_GATE_EN;
554                         REG_WRITE(dpll_reg, reg_val);
555                         REG_READ(dpll_reg);
556                         udelay(500);
557                 }
558
559                 reg_val |= DPLL_VCO_ENABLE;
560                 REG_WRITE(dpll_reg, reg_val);
561                 REG_READ(dpll_reg);
562                 udelay(500);
563
564                 /* FIXME: add timeout */
565                 while (!(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK))
566                         cpu_relax();
567         }
568
569         /* Enable pipe */
570         reg_val = REG_READ(pipeconf_reg);
571         if (!(reg_val & PIPEACONF_ENABLE)) {
572                 reg_val |= PIPEACONF_ENABLE;
573                 REG_WRITE(pipeconf_reg, reg_val);
574                 REG_READ(pipeconf_reg);
575                 udelay(500);
576                 mdfldWaitForPipeEnable(dev, pipe);
577         }
578
579         /* Enable plane */
580         reg_val = REG_READ(dspcntr_reg);
581         if (!(reg_val & DISPLAY_PLANE_ENABLE)) {
582                 reg_val |= DISPLAY_PLANE_ENABLE;
583                 REG_WRITE(dspcntr_reg, reg_val);
584                 REG_READ(dspcntr_reg);
585                 udelay(500);
586         }
587
588         gma_power_end(dev);
589
590         /* Clean IN_DSR flag */
591         dbi_output->mode_flags &= ~MODE_SETTING_IN_DSR;
592
593         return 0;
594 }
595
596 int mdfld_dpu_exit_dsr(struct drm_device *dev)
597 {
598         struct mdfld_dsi_dbi_output **dbi_output;
599         struct drm_psb_private *dev_priv = dev->dev_private;
600         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
601         int i;
602         int pipe;
603
604         dbi_output = dpu_info->dbi_outputs;
605
606         for (i = 0; i < dpu_info->dbi_output_num; i++) {
607                 /* If this output is not in DSR mode, don't call exit dsr */
608                 if (dbi_output[i]->mode_flags & MODE_SETTING_IN_DSR)
609                         __mdfld_dbi_exit_dsr(dbi_output[i],
610                                         dbi_output[i]->channel_num ? 2 : 0);
611         }
612
613         /* Enable TE interrupt */
614         for (i = 0; i < dpu_info->dbi_output_num; i++) {
615                 /* If this output is not in DSR mode, don't call exit dsr */
616                 pipe = dbi_output[i]->channel_num ? 2 : 0;
617                 if (dbi_output[i]->dbi_panel_on && pipe) {
618                         mdfld_disable_te(dev, 0);
619                         mdfld_enable_te(dev, 2);
620                 } else if (dbi_output[i]->dbi_panel_on && !pipe) {
621                         mdfld_disable_te(dev, 2);
622                         mdfld_enable_te(dev, 0);
623                 }
624         }
625         return 0;
626 }
627
628 static int mdfld_dpu_enter_dsr(struct drm_device *dev)
629 {
630         struct drm_psb_private *dev_priv = dev->dev_private;
631         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
632         struct mdfld_dsi_dbi_output **dbi_output;
633         int i;
634
635         dbi_output = dpu_info->dbi_outputs;
636
637         for (i = 0; i < dpu_info->dbi_output_num; i++) {
638                 /* If output is off or already in DSR state, don't re-enter */
639                 if (dbi_output[i]->dbi_panel_on &&
640                    !(dbi_output[i]->mode_flags & MODE_SETTING_IN_DSR)) {
641                         mdfld_dsi_dbi_enter_dsr(dbi_output[i],
642                                 dbi_output[i]->channel_num ? 2 : 0);
643                 }
644         }
645
646         return 0;
647 }
648
649 static void mdfld_dbi_dpu_timer_func(unsigned long data)
650 {
651         struct drm_device *dev = (struct drm_device *)data;
652         struct drm_psb_private *dev_priv = dev->dev_private;
653         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
654         struct timer_list *dpu_timer = &dpu_info->dpu_timer;
655         unsigned long flags;
656
657         if (dpu_info->pending) {
658                 dpu_info->idle_count = 0;
659                 /* Update panel fb with damaged area */
660                 mdfld_dpu_update_fb(dev);
661         } else {
662                 dpu_info->idle_count++;
663         }
664
665         if (dpu_info->idle_count >= MDFLD_MAX_IDLE_COUNT) {
666                 mdfld_dpu_enter_dsr(dev);
667                 /* Stop timer by return */
668                 return;
669         }
670
671         spin_lock_irqsave(&dpu_info->dpu_timer_lock, flags);
672         if (!timer_pending(dpu_timer)) {
673                 dpu_timer->expires = jiffies + MDFLD_DSR_DELAY;
674                 add_timer(dpu_timer);
675         }
676         spin_unlock_irqrestore(&dpu_info->dpu_timer_lock, flags);
677 }
678
679 void mdfld_dpu_update_panel(struct drm_device *dev)
680 {
681         struct drm_psb_private *dev_priv = dev->dev_private;
682         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
683
684         if (dpu_info->pending) {
685                 dpu_info->idle_count = 0;
686
687                 /*update panel fb with damaged area*/
688                 mdfld_dpu_update_fb(dev);
689         } else {
690                 dpu_info->idle_count++;
691         }
692
693         if (dpu_info->idle_count >= MDFLD_MAX_IDLE_COUNT) {
694                 /*enter dsr*/
695                 mdfld_dpu_enter_dsr(dev);
696         }
697 }
698
699 static int mdfld_dbi_dpu_timer_init(struct drm_device *dev,
700                                 struct mdfld_dbi_dpu_info *dpu_info)
701 {
702         struct timer_list *dpu_timer = &dpu_info->dpu_timer;
703         unsigned long flags;
704
705         spin_lock_init(&dpu_info->dpu_timer_lock);
706         spin_lock_irqsave(&dpu_info->dpu_timer_lock, flags);
707
708         init_timer(dpu_timer);
709
710         dpu_timer->data = (unsigned long)dev;
711         dpu_timer->function = mdfld_dbi_dpu_timer_func;
712         dpu_timer->expires = jiffies + MDFLD_DSR_DELAY;
713
714         spin_unlock_irqrestore(&dpu_info->dpu_timer_lock, flags);
715
716         return 0;
717 }
718
719 void mdfld_dbi_dpu_timer_start(struct mdfld_dbi_dpu_info *dpu_info)
720 {
721         struct timer_list *dpu_timer = &dpu_info->dpu_timer;
722         unsigned long flags;
723
724         spin_lock_irqsave(&dpu_info->dpu_timer_lock, flags);
725         if (!timer_pending(dpu_timer)) {
726                 dpu_timer->expires = jiffies + MDFLD_DSR_DELAY;
727                 add_timer(dpu_timer);
728         }
729         spin_unlock_irqrestore(&dpu_info->dpu_timer_lock, flags);
730 }
731
732 int mdfld_dbi_dpu_init(struct drm_device *dev)
733 {
734         struct drm_psb_private *dev_priv = dev->dev_private;
735         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
736
737         if (!dpu_info || IS_ERR(dpu_info)) {
738                 dpu_info = kzalloc(sizeof(struct mdfld_dbi_dpu_info),
739                                                                 GFP_KERNEL);
740                 if (!dpu_info) {
741                         DRM_ERROR("No memory\n");
742                         return -ENOMEM;
743                 }
744                 dev_priv->dbi_dpu_info = dpu_info;
745         }
746
747         dpu_info->dev = dev;
748
749         dpu_info->cursors[0].size = MDFLD_CURSOR_SIZE;
750         dpu_info->cursors[1].size = MDFLD_CURSOR_SIZE;
751
752         /*init dpu_update_lock*/
753         spin_lock_init(&dpu_info->dpu_update_lock);
754
755         /*init dpu refresh timer*/
756         mdfld_dbi_dpu_timer_init(dev, dpu_info);
757
758         /*init pipe damage area*/
759         mdfld_dpu_init_damage(dpu_info, 0);
760         mdfld_dpu_init_damage(dpu_info, 2);
761
762         return 0;
763 }
764
765 void mdfld_dbi_dpu_exit(struct drm_device *dev)
766 {
767         struct drm_psb_private *dev_priv = dev->dev_private;
768         struct mdfld_dbi_dpu_info *dpu_info = dev_priv->dbi_dpu_info;
769
770         if (!dpu_info)
771                 return;
772
773         del_timer_sync(&dpu_info->dpu_timer);
774         kfree(dpu_info);
775         dev_priv->dbi_dpu_info = NULL;
776 }
777
778