blob: a4e2ff442b1f8ab1d3c2abe7bc2b0c3ca463bdc9 [file] [log] [blame]
Alan Cox3a970ac2011-07-15 17:35:49 +01001/*
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
35static 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 }
98cursor_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
132static 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 */
154static 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
161int 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
196int 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
232int 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
249static 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
272static 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
307static 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 */
316static 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
362static 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
382static 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 */
Alan Coxc6036852011-07-15 17:46:58 +0100421 if (!ret && dev_priv->dsr_enable) {
Alan Cox3a970ac2011-07-15 17:35:49 +0100422 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
430static 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
512static 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
Alan Coxc6036852011-07-15 17:46:58 +0100530 /* If mode setting on-going, back off */
Alan Cox3a970ac2011-07-15 17:35:49 +0100531 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
Alan Coxc6036852011-07-15 17:46:58 +0100545 if (!gma_power_begin(dev, true))
Alan Cox3a970ac2011-07-15 17:35:49 +0100546 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
Alan Coxc6036852011-07-15 17:46:58 +0100588 gma_power_end(dev);
Alan Cox3a970ac2011-07-15 17:35:49 +0100589
Alan Coxc6036852011-07-15 17:46:58 +0100590 /* Clean IN_DSR flag */
Alan Cox3a970ac2011-07-15 17:35:49 +0100591 dbi_output->mode_flags &= ~MODE_SETTING_IN_DSR;
592
593 return 0;
594}
595
596int 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
628static 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
649static 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
679void 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
699static 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
719void 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
732int 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
765void 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