Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dispc.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/video/omap2/dss/dispc.c
3  *
4  * Copyright (C) 2009 Nokia Corporation
5  * Author: Tomi Valkeinen <[email protected]>
6  *
7  * Some code and ideas taken from drivers/video/omap/ driver
8  * by Imre Deak.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published by
12  * the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #define DSS_SUBSYS_NAME "DISPC"
24 
25 #include <linux/kernel.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/vmalloc.h>
28 #include <linux/export.h>
29 #include <linux/clk.h>
30 #include <linux/io.h>
31 #include <linux/jiffies.h>
32 #include <linux/seq_file.h>
33 #include <linux/delay.h>
34 #include <linux/workqueue.h>
35 #include <linux/hardirq.h>
36 #include <linux/interrupt.h>
37 #include <linux/platform_device.h>
38 #include <linux/pm_runtime.h>
39 
40 #include <plat/cpu.h>
41 
42 #include <video/omapdss.h>
43 
44 #include "dss.h"
45 #include "dss_features.h"
46 #include "dispc.h"
47 
48 /* DISPC */
49 #define DISPC_SZ_REGS SZ_4K
50 
51 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
52  DISPC_IRQ_OCP_ERR | \
53  DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
54  DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
55  DISPC_IRQ_SYNC_LOST | \
56  DISPC_IRQ_SYNC_LOST_DIGIT)
57 
58 #define DISPC_MAX_NR_ISRS 8
59 
62  void *arg;
64 };
65 
70 };
71 
72 #define REG_GET(idx, start, end) \
73  FLD_GET(dispc_read_reg(idx), start, end)
74 
75 #define REG_FLD_MOD(idx, val, start, end) \
76  dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
77 
79  unsigned long last_reset;
80  unsigned irq_count;
81  unsigned irqs[32];
82 };
83 
92  const struct omap_video_timings *mgr_timings,
93  u16 width, u16 height, u16 out_width, u16 out_height,
94  enum omap_color_mode color_mode, bool *five_taps,
95  int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
96  u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
97  unsigned long (*calc_core_clk) (enum omap_plane plane,
98  u16 width, u16 height, u16 out_width, u16 out_height,
99  bool mem_to_mem);
101 
102  /* swap GFX & WB fifos */
104 };
105 
106 #define DISPC_MAX_NR_FIFOS 5
107 
108 static struct {
110  void __iomem *base;
111 
113 
114  int irq;
115  struct clk *dss_clk;
116 
118  /* maps which plane is using a fifo. fifo-id -> plane-id */
120 
126 
127  bool ctx_valid;
128  u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
129 
130  const struct dispc_features *feat;
131 
132 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
133  spinlock_t irq_stats_lock;
134  struct dispc_irq_stats irq_stats;
135 #endif
136 } dispc;
137 
139  /* used for all color formats for OMAP3 and earlier
140  * and for RGB and Y color component on OMAP4
141  */
143  /* used for UV component for
144  * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
145  * color formats on OMAP4
146  */
148 };
149 
160  /* used to maintain a count of the above fields */
162 };
163 
164 static const struct {
165  const char *name;
170 } mgr_desc[] = {
172  .name = "LCD",
173  .vsync_irq = DISPC_IRQ_VSYNC,
174  .framedone_irq = DISPC_IRQ_FRAMEDONE,
175  .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
176  .reg_desc = {
177  [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
178  [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
179  [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 },
181  [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 },
182  [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 },
184  [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 },
186  },
187  },
189  .name = "DIGIT",
191  .framedone_irq = 0,
192  .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
193  .reg_desc = {
194  [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
195  [DISPC_MGR_FLD_STNTFT] = { },
196  [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 },
198  [DISPC_MGR_FLD_STALLMODE] = { },
199  [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 },
201  [DISPC_MGR_FLD_CPR] = { },
203  },
204  },
206  .name = "LCD2",
207  .vsync_irq = DISPC_IRQ_VSYNC2,
208  .framedone_irq = DISPC_IRQ_FRAMEDONE2,
209  .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
210  .reg_desc = {
211  [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
212  [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
213  [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 },
215  [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 },
216  [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 },
218  [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 },
220  },
221  },
223  .name = "LCD3",
224  .vsync_irq = DISPC_IRQ_VSYNC3,
225  .framedone_irq = DISPC_IRQ_FRAMEDONE3,
226  .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
227  .reg_desc = {
228  [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
229  [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
230  [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 },
232  [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 },
233  [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 },
235  [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 },
237  },
238  },
239 };
240 
242  int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
244 };
245 
246 static void _omap_dispc_set_irqs(void);
247 static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
248 static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
249 
250 static inline void dispc_write_reg(const u16 idx, u32 val)
251 {
252  __raw_writel(val, dispc.base + idx);
253 }
254 
255 static inline u32 dispc_read_reg(const u16 idx)
256 {
257  return __raw_readl(dispc.base + idx);
258 }
259 
260 static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
261 {
262  const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld];
263  return REG_GET(rfld.reg, rfld.high, rfld.low);
264 }
265 
266 static void mgr_fld_write(enum omap_channel channel,
267  enum mgr_reg_fields regfld, int val) {
268  const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld];
269  REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
270 }
271 
272 #define SR(reg) \
273  dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
274 #define RR(reg) \
275  dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
276 
277 static void dispc_save_context(void)
278 {
279  int i, j;
280 
281  DSSDBG("dispc_save_context\n");
282 
283  SR(IRQENABLE);
284  SR(CONTROL);
285  SR(CONFIG);
286  SR(LINE_NUMBER);
289  SR(GLOBAL_ALPHA);
291  SR(CONTROL2);
292  SR(CONFIG2);
293  }
295  SR(CONTROL3);
296  SR(CONFIG3);
297  }
298 
299  for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
300  SR(DEFAULT_COLOR(i));
301  SR(TRANS_COLOR(i));
302  SR(SIZE_MGR(i));
303  if (i == OMAP_DSS_CHANNEL_DIGIT)
304  continue;
305  SR(TIMING_H(i));
306  SR(TIMING_V(i));
307  SR(POL_FREQ(i));
308  SR(DIVISORo(i));
309 
310  SR(DATA_CYCLE1(i));
311  SR(DATA_CYCLE2(i));
312  SR(DATA_CYCLE3(i));
313 
314  if (dss_has_feature(FEAT_CPR)) {
315  SR(CPR_COEF_R(i));
316  SR(CPR_COEF_G(i));
317  SR(CPR_COEF_B(i));
318  }
319  }
320 
321  for (i = 0; i < dss_feat_get_num_ovls(); i++) {
322  SR(OVL_BA0(i));
323  SR(OVL_BA1(i));
324  SR(OVL_POSITION(i));
325  SR(OVL_SIZE(i));
326  SR(OVL_ATTRIBUTES(i));
327  SR(OVL_FIFO_THRESHOLD(i));
328  SR(OVL_ROW_INC(i));
329  SR(OVL_PIXEL_INC(i));
331  SR(OVL_PRELOAD(i));
332  if (i == OMAP_DSS_GFX) {
333  SR(OVL_WINDOW_SKIP(i));
334  SR(OVL_TABLE_BA(i));
335  continue;
336  }
337  SR(OVL_FIR(i));
338  SR(OVL_PICTURE_SIZE(i));
339  SR(OVL_ACCU0(i));
340  SR(OVL_ACCU1(i));
341 
342  for (j = 0; j < 8; j++)
343  SR(OVL_FIR_COEF_H(i, j));
344 
345  for (j = 0; j < 8; j++)
346  SR(OVL_FIR_COEF_HV(i, j));
347 
348  for (j = 0; j < 5; j++)
349  SR(OVL_CONV_COEF(i, j));
350 
352  for (j = 0; j < 8; j++)
353  SR(OVL_FIR_COEF_V(i, j));
354  }
355 
357  SR(OVL_BA0_UV(i));
358  SR(OVL_BA1_UV(i));
359  SR(OVL_FIR2(i));
360  SR(OVL_ACCU2_0(i));
361  SR(OVL_ACCU2_1(i));
362 
363  for (j = 0; j < 8; j++)
364  SR(OVL_FIR_COEF_H2(i, j));
365 
366  for (j = 0; j < 8; j++)
367  SR(OVL_FIR_COEF_HV2(i, j));
368 
369  for (j = 0; j < 8; j++)
370  SR(OVL_FIR_COEF_V2(i, j));
371  }
373  SR(OVL_ATTRIBUTES2(i));
374  }
375 
377  SR(DIVISOR);
378 
379  dispc.ctx_loss_cnt = dss_get_ctx_loss_count(&dispc.pdev->dev);
380  dispc.ctx_valid = true;
381 
382  DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt);
383 }
384 
385 static void dispc_restore_context(void)
386 {
387  int i, j, ctx;
388 
389  DSSDBG("dispc_restore_context\n");
390 
391  if (!dispc.ctx_valid)
392  return;
393 
394  ctx = dss_get_ctx_loss_count(&dispc.pdev->dev);
395 
396  if (ctx >= 0 && ctx == dispc.ctx_loss_cnt)
397  return;
398 
399  DSSDBG("ctx_loss_count: saved %d, current %d\n",
400  dispc.ctx_loss_cnt, ctx);
401 
402  /*RR(IRQENABLE);*/
403  /*RR(CONTROL);*/
404  RR(CONFIG);
405  RR(LINE_NUMBER);
408  RR(GLOBAL_ALPHA);
410  RR(CONFIG2);
412  RR(CONFIG3);
413 
414  for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
415  RR(DEFAULT_COLOR(i));
416  RR(TRANS_COLOR(i));
417  RR(SIZE_MGR(i));
418  if (i == OMAP_DSS_CHANNEL_DIGIT)
419  continue;
420  RR(TIMING_H(i));
421  RR(TIMING_V(i));
422  RR(POL_FREQ(i));
423  RR(DIVISORo(i));
424 
425  RR(DATA_CYCLE1(i));
426  RR(DATA_CYCLE2(i));
427  RR(DATA_CYCLE3(i));
428 
429  if (dss_has_feature(FEAT_CPR)) {
430  RR(CPR_COEF_R(i));
431  RR(CPR_COEF_G(i));
432  RR(CPR_COEF_B(i));
433  }
434  }
435 
436  for (i = 0; i < dss_feat_get_num_ovls(); i++) {
437  RR(OVL_BA0(i));
438  RR(OVL_BA1(i));
439  RR(OVL_POSITION(i));
440  RR(OVL_SIZE(i));
441  RR(OVL_ATTRIBUTES(i));
442  RR(OVL_FIFO_THRESHOLD(i));
443  RR(OVL_ROW_INC(i));
444  RR(OVL_PIXEL_INC(i));
446  RR(OVL_PRELOAD(i));
447  if (i == OMAP_DSS_GFX) {
448  RR(OVL_WINDOW_SKIP(i));
449  RR(OVL_TABLE_BA(i));
450  continue;
451  }
452  RR(OVL_FIR(i));
453  RR(OVL_PICTURE_SIZE(i));
454  RR(OVL_ACCU0(i));
455  RR(OVL_ACCU1(i));
456 
457  for (j = 0; j < 8; j++)
458  RR(OVL_FIR_COEF_H(i, j));
459 
460  for (j = 0; j < 8; j++)
461  RR(OVL_FIR_COEF_HV(i, j));
462 
463  for (j = 0; j < 5; j++)
464  RR(OVL_CONV_COEF(i, j));
465 
467  for (j = 0; j < 8; j++)
468  RR(OVL_FIR_COEF_V(i, j));
469  }
470 
472  RR(OVL_BA0_UV(i));
473  RR(OVL_BA1_UV(i));
474  RR(OVL_FIR2(i));
475  RR(OVL_ACCU2_0(i));
476  RR(OVL_ACCU2_1(i));
477 
478  for (j = 0; j < 8; j++)
479  RR(OVL_FIR_COEF_H2(i, j));
480 
481  for (j = 0; j < 8; j++)
482  RR(OVL_FIR_COEF_HV2(i, j));
483 
484  for (j = 0; j < 8; j++)
485  RR(OVL_FIR_COEF_V2(i, j));
486  }
488  RR(OVL_ATTRIBUTES2(i));
489  }
490 
492  RR(DIVISOR);
493 
494  /* enable last, because LCD & DIGIT enable are here */
495  RR(CONTROL);
497  RR(CONTROL2);
499  RR(CONTROL3);
500  /* clear spurious SYNC_LOST_DIGIT interrupts */
501  dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
502 
503  /*
504  * enable last so IRQs won't trigger before
505  * the context is fully restored
506  */
507  RR(IRQENABLE);
508 
509  DSSDBG("context restored\n");
510 }
511 
512 #undef SR
513 #undef RR
514 
516 {
517  int r;
518 
519  DSSDBG("dispc_runtime_get\n");
520 
521  r = pm_runtime_get_sync(&dispc.pdev->dev);
522  WARN_ON(r < 0);
523  return r < 0 ? r : 0;
524 }
525 
527 {
528  int r;
529 
530  DSSDBG("dispc_runtime_put\n");
531 
532  r = pm_runtime_put_sync(&dispc.pdev->dev);
533  WARN_ON(r < 0 && r != -ENOSYS);
534 }
535 
537 {
538  return mgr_desc[channel].vsync_irq;
539 }
540 
542 {
543  return mgr_desc[channel].framedone_irq;
544 }
545 
547 {
548  return DISPC_IRQ_FRAMEDONEWB;
549 }
550 
552 {
553  return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
554 }
555 
557 {
558  bool enable_bit, go_bit;
559 
560  /* if the channel is not enabled, we don't need GO */
561  enable_bit = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE) == 1;
562 
563  if (!enable_bit)
564  return;
565 
566  go_bit = mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
567 
568  if (go_bit) {
569  DSSERR("GO bit not down for channel %d\n", channel);
570  return;
571  }
572 
573  DSSDBG("GO %s\n", mgr_desc[channel].name);
574 
575  mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
576 }
577 
579 {
580  return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
581 }
582 
583 void dispc_wb_go(void)
584 {
586  bool enable, go;
587 
588  enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
589 
590  if (!enable)
591  return;
592 
593  go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
594  if (go) {
595  DSSERR("GO bit not down for WB\n");
596  return;
597  }
598 
599  REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
600 }
601 
602 static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
603 {
604  dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
605 }
606 
607 static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
608 {
609  dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
610 }
611 
612 static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value)
613 {
614  dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
615 }
616 
617 static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
618 {
619  BUG_ON(plane == OMAP_DSS_GFX);
620 
621  dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
622 }
623 
624 static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg,
625  u32 value)
626 {
627  BUG_ON(plane == OMAP_DSS_GFX);
628 
629  dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
630 }
631 
632 static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
633 {
634  BUG_ON(plane == OMAP_DSS_GFX);
635 
636  dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
637 }
638 
639 static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
640  int fir_vinc, int five_taps,
641  enum omap_color_component color_comp)
642 {
643  const struct dispc_coef *h_coef, *v_coef;
644  int i;
645 
646  h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
647  v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
648 
649  for (i = 0; i < 8; i++) {
650  u32 h, hv;
651 
652  h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
653  | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
654  | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
655  | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
656  hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
657  | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
658  | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
659  | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
660 
661  if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
662  dispc_ovl_write_firh_reg(plane, i, h);
663  dispc_ovl_write_firhv_reg(plane, i, hv);
664  } else {
665  dispc_ovl_write_firh2_reg(plane, i, h);
666  dispc_ovl_write_firhv2_reg(plane, i, hv);
667  }
668 
669  }
670 
671  if (five_taps) {
672  for (i = 0; i < 8; i++) {
673  u32 v;
674  v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
675  | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
676  if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
677  dispc_ovl_write_firv_reg(plane, i, v);
678  else
679  dispc_ovl_write_firv2_reg(plane, i, v);
680  }
681  }
682 }
683 
684 
685 static void dispc_ovl_write_color_conv_coef(enum omap_plane plane,
686  const struct color_conv_coef *ct)
687 {
688 #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
689 
690  dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
691  dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
692  dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
693  dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
694  dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
695 
696  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
697 
698 #undef CVAL
699 }
700 
701 static void dispc_setup_color_conv_coef(void)
702 {
703  int i;
704  int num_ovl = dss_feat_get_num_ovls();
705  int num_wb = dss_feat_get_num_wbs();
706  const struct color_conv_coef ctbl_bt601_5_ovl = {
707  298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
708  };
709  const struct color_conv_coef ctbl_bt601_5_wb = {
710  66, 112, -38, 129, -94, -74, 25, -18, 112, 0,
711  };
712 
713  for (i = 1; i < num_ovl; i++)
714  dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
715 
716  for (; i < num_wb; i++)
717  dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb);
718 }
719 
720 static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
721 {
722  dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
723 }
724 
725 static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr)
726 {
727  dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
728 }
729 
730 static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr)
731 {
732  dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
733 }
734 
735 static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
736 {
737  dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
738 }
739 
740 static void dispc_ovl_set_pos(enum omap_plane plane,
741  enum omap_overlay_caps caps, int x, int y)
742 {
743  u32 val;
744 
745  if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
746  return;
747 
748  val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
749 
750  dispc_write_reg(DISPC_OVL_POSITION(plane), val);
751 }
752 
753 static void dispc_ovl_set_input_size(enum omap_plane plane, int width,
754  int height)
755 {
756  u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
757 
758  if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
759  dispc_write_reg(DISPC_OVL_SIZE(plane), val);
760  else
761  dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
762 }
763 
764 static void dispc_ovl_set_output_size(enum omap_plane plane, int width,
765  int height)
766 {
767  u32 val;
768 
769  BUG_ON(plane == OMAP_DSS_GFX);
770 
771  val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
772 
773  if (plane == OMAP_DSS_WB)
774  dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
775  else
776  dispc_write_reg(DISPC_OVL_SIZE(plane), val);
777 }
778 
779 static void dispc_ovl_set_zorder(enum omap_plane plane,
780  enum omap_overlay_caps caps, u8 zorder)
781 {
782  if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
783  return;
784 
785  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
786 }
787 
788 static void dispc_ovl_enable_zorder_planes(void)
789 {
790  int i;
791 
793  return;
794 
795  for (i = 0; i < dss_feat_get_num_ovls(); i++)
796  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
797 }
798 
799 static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane,
800  enum omap_overlay_caps caps, bool enable)
801 {
802  if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
803  return;
804 
805  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
806 }
807 
808 static void dispc_ovl_setup_global_alpha(enum omap_plane plane,
809  enum omap_overlay_caps caps, u8 global_alpha)
810 {
811  static const unsigned shifts[] = { 0, 8, 16, 24, };
812  int shift;
813 
814  if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
815  return;
816 
817  shift = shifts[plane];
818  REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
819 }
820 
821 static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc)
822 {
823  dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
824 }
825 
826 static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc)
827 {
828  dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
829 }
830 
831 static void dispc_ovl_set_color_mode(enum omap_plane plane,
832  enum omap_color_mode color_mode)
833 {
834  u32 m = 0;
835  if (plane != OMAP_DSS_GFX) {
836  switch (color_mode) {
837  case OMAP_DSS_COLOR_NV12:
838  m = 0x0; break;
840  m = 0x1; break;
842  m = 0x2; break;
844  m = 0x4; break;
846  m = 0x5; break;
848  m = 0x6; break;
850  m = 0x7; break;
852  m = 0x8; break;
854  m = 0x9; break;
855  case OMAP_DSS_COLOR_YUV2:
856  m = 0xa; break;
857  case OMAP_DSS_COLOR_UYVY:
858  m = 0xb; break;
860  m = 0xc; break;
862  m = 0xd; break;
864  m = 0xe; break;
866  m = 0xf; break;
867  default:
868  BUG(); return;
869  }
870  } else {
871  switch (color_mode) {
873  m = 0x0; break;
875  m = 0x1; break;
877  m = 0x2; break;
879  m = 0x3; break;
881  m = 0x4; break;
883  m = 0x5; break;
885  m = 0x6; break;
887  m = 0x7; break;
889  m = 0x8; break;
891  m = 0x9; break;
893  m = 0xa; break;
895  m = 0xb; break;
897  m = 0xc; break;
899  m = 0xd; break;
901  m = 0xe; break;
903  m = 0xf; break;
904  default:
905  BUG(); return;
906  }
907  }
908 
909  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
910 }
911 
912 static void dispc_ovl_configure_burst_type(enum omap_plane plane,
913  enum omap_dss_rotation_type rotation_type)
914 {
915  if (dss_has_feature(FEAT_BURST_2D) == 0)
916  return;
917 
918  if (rotation_type == OMAP_DSS_ROT_TILER)
919  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
920  else
921  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
922 }
923 
925 {
926  int shift;
927  u32 val;
928  int chan = 0, chan2 = 0;
929 
930  switch (plane) {
931  case OMAP_DSS_GFX:
932  shift = 8;
933  break;
934  case OMAP_DSS_VIDEO1:
935  case OMAP_DSS_VIDEO2:
936  case OMAP_DSS_VIDEO3:
937  shift = 16;
938  break;
939  default:
940  BUG();
941  return;
942  }
943 
944  val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
946  switch (channel) {
948  chan = 0;
949  chan2 = 0;
950  break;
952  chan = 1;
953  chan2 = 0;
954  break;
956  chan = 0;
957  chan2 = 1;
958  break;
961  chan = 0;
962  chan2 = 2;
963  } else {
964  BUG();
965  return;
966  }
967  break;
968  default:
969  BUG();
970  return;
971  }
972 
973  val = FLD_MOD(val, chan, shift, shift);
974  val = FLD_MOD(val, chan2, 31, 30);
975  } else {
976  val = FLD_MOD(val, channel, shift, shift);
977  }
978  dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
979 }
980 
981 static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
982 {
983  int shift;
984  u32 val;
985  enum omap_channel channel;
986 
987  switch (plane) {
988  case OMAP_DSS_GFX:
989  shift = 8;
990  break;
991  case OMAP_DSS_VIDEO1:
992  case OMAP_DSS_VIDEO2:
993  case OMAP_DSS_VIDEO3:
994  shift = 16;
995  break;
996  default:
997  BUG();
998  return 0;
999  }
1000 
1001  val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1002 
1004  if (FLD_GET(val, 31, 30) == 0)
1005  channel = FLD_GET(val, shift, shift);
1006  else if (FLD_GET(val, 31, 30) == 1)
1007  channel = OMAP_DSS_CHANNEL_LCD2;
1008  else
1009  channel = OMAP_DSS_CHANNEL_LCD3;
1010  } else if (dss_has_feature(FEAT_MGR_LCD2)) {
1011  if (FLD_GET(val, 31, 30) == 0)
1012  channel = FLD_GET(val, shift, shift);
1013  else
1014  channel = OMAP_DSS_CHANNEL_LCD2;
1015  } else {
1016  channel = FLD_GET(val, shift, shift);
1017  }
1018 
1019  return channel;
1020 }
1021 
1023 {
1024  enum omap_plane plane = OMAP_DSS_WB;
1025 
1026  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
1027 }
1028 
1029 static void dispc_ovl_set_burst_size(enum omap_plane plane,
1030  enum omap_burst_size burst_size)
1031 {
1032  static const unsigned shifts[] = { 6, 14, 14, 14, 14, };
1033  int shift;
1034 
1035  shift = shifts[plane];
1036  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
1037 }
1038 
1039 static void dispc_configure_burst_sizes(void)
1040 {
1041  int i;
1042  const int burst_size = BURST_SIZE_X8;
1043 
1044  /* Configure burst size always to maximum size */
1045  for (i = 0; i < omap_dss_get_num_overlays(); ++i)
1046  dispc_ovl_set_burst_size(i, burst_size);
1047 }
1048 
1049 static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
1050 {
1051  unsigned unit = dss_feat_get_burst_size_unit();
1052  /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
1053  return unit * 8;
1054 }
1055 
1056 void dispc_enable_gamma_table(bool enable)
1057 {
1058  /*
1059  * This is partially implemented to support only disabling of
1060  * the gamma table.
1061  */
1062  if (enable) {
1063  DSSWARN("Gamma table enabling for TV not yet supported");
1064  return;
1065  }
1066 
1067  REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
1068 }
1069 
1070 static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
1071 {
1072  if (channel == OMAP_DSS_CHANNEL_DIGIT)
1073  return;
1074 
1075  mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);
1076 }
1077 
1078 static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
1079  struct omap_dss_cpr_coefs *coefs)
1080 {
1081  u32 coef_r, coef_g, coef_b;
1082 
1083  if (!dss_mgr_is_lcd(channel))
1084  return;
1085 
1086  coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
1087  FLD_VAL(coefs->rb, 9, 0);
1088  coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
1089  FLD_VAL(coefs->gb, 9, 0);
1090  coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
1091  FLD_VAL(coefs->bb, 9, 0);
1092 
1093  dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
1094  dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
1095  dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
1096 }
1097 
1098 static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
1099 {
1100  u32 val;
1101 
1102  BUG_ON(plane == OMAP_DSS_GFX);
1103 
1104  val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1105  val = FLD_MOD(val, enable, 9, 9);
1106  dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
1107 }
1108 
1109 static void dispc_ovl_enable_replication(enum omap_plane plane,
1110  enum omap_overlay_caps caps, bool enable)
1111 {
1112  static const unsigned shifts[] = { 5, 10, 10, 10 };
1113  int shift;
1114 
1115  if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
1116  return;
1117 
1118  shift = shifts[plane];
1119  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
1120 }
1121 
1122 static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
1123  u16 height)
1124 {
1125  u32 val;
1126 
1127  val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
1128  dispc_write_reg(DISPC_SIZE_MGR(channel), val);
1129 }
1130 
1131 static void dispc_init_fifos(void)
1132 {
1133  u32 size;
1134  int fifo;
1135  u8 start, end;
1136  u32 unit;
1137 
1139 
1141 
1142  for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1143  size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
1144  size *= unit;
1145  dispc.fifo_size[fifo] = size;
1146 
1147  /*
1148  * By default fifos are mapped directly to overlays, fifo 0 to
1149  * ovl 0, fifo 1 to ovl 1, etc.
1150  */
1151  dispc.fifo_assignment[fifo] = fifo;
1152  }
1153 
1154  /*
1155  * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
1156  * causes problems with certain use cases, like using the tiler in 2D
1157  * mode. The below hack swaps the fifos of GFX and WB planes, thus
1158  * giving GFX plane a larger fifo. WB but should work fine with a
1159  * smaller fifo.
1160  */
1161  if (dispc.feat->gfx_fifo_workaround) {
1162  u32 v;
1163 
1164  v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
1165 
1166  v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
1167  v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
1168  v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
1169  v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
1170 
1171  dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
1172 
1173  dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
1174  dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
1175  }
1176 }
1177 
1178 static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
1179 {
1180  int fifo;
1181  u32 size = 0;
1182 
1183  for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1184  if (dispc.fifo_assignment[fifo] == plane)
1185  size += dispc.fifo_size[fifo];
1186  }
1187 
1188  return size;
1189 }
1190 
1192 {
1193  u8 hi_start, hi_end, lo_start, lo_end;
1194  u32 unit;
1195 
1197 
1198  WARN_ON(low % unit != 0);
1199  WARN_ON(high % unit != 0);
1200 
1201  low /= unit;
1202  high /= unit;
1203 
1206 
1207  DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
1208  plane,
1210  lo_start, lo_end) * unit,
1212  hi_start, hi_end) * unit,
1213  low * unit, high * unit);
1214 
1215  dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
1216  FLD_VAL(high, hi_start, hi_end) |
1217  FLD_VAL(low, lo_start, lo_end));
1218 }
1219 
1220 void dispc_enable_fifomerge(bool enable)
1221 {
1223  WARN_ON(enable);
1224  return;
1225  }
1226 
1227  DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1228  REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1229 }
1230 
1232  u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
1233  bool manual_update)
1234 {
1235  /*
1236  * All sizes are in bytes. Both the buffer and burst are made of
1237  * buffer_units, and the fifo thresholds must be buffer_unit aligned.
1238  */
1239 
1240  unsigned buf_unit = dss_feat_get_buffer_size_unit();
1241  unsigned ovl_fifo_size, total_fifo_size, burst_size;
1242  int i;
1243 
1244  burst_size = dispc_ovl_get_burst_size(plane);
1245  ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
1246 
1247  if (use_fifomerge) {
1248  total_fifo_size = 0;
1249  for (i = 0; i < omap_dss_get_num_overlays(); ++i)
1250  total_fifo_size += dispc_ovl_get_fifo_size(i);
1251  } else {
1252  total_fifo_size = ovl_fifo_size;
1253  }
1254 
1255  /*
1256  * We use the same low threshold for both fifomerge and non-fifomerge
1257  * cases, but for fifomerge we calculate the high threshold using the
1258  * combined fifo size
1259  */
1260 
1261  if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
1262  *fifo_low = ovl_fifo_size - burst_size * 2;
1263  *fifo_high = total_fifo_size - burst_size;
1264  } else if (plane == OMAP_DSS_WB) {
1265  /*
1266  * Most optimal configuration for writeback is to push out data
1267  * to the interconnect the moment writeback pushes enough pixels
1268  * in the FIFO to form a burst
1269  */
1270  *fifo_low = 0;
1271  *fifo_high = burst_size;
1272  } else {
1273  *fifo_low = ovl_fifo_size - burst_size;
1274  *fifo_high = total_fifo_size - buf_unit;
1275  }
1276 }
1277 
1278 static void dispc_ovl_set_fir(enum omap_plane plane,
1279  int hinc, int vinc,
1280  enum omap_color_component color_comp)
1281 {
1282  u32 val;
1283 
1284  if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
1285  u8 hinc_start, hinc_end, vinc_start, vinc_end;
1286 
1288  &hinc_start, &hinc_end);
1290  &vinc_start, &vinc_end);
1291  val = FLD_VAL(vinc, vinc_start, vinc_end) |
1292  FLD_VAL(hinc, hinc_start, hinc_end);
1293 
1294  dispc_write_reg(DISPC_OVL_FIR(plane), val);
1295  } else {
1296  val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1297  dispc_write_reg(DISPC_OVL_FIR2(plane), val);
1298  }
1299 }
1300 
1301 static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1302 {
1303  u32 val;
1304  u8 hor_start, hor_end, vert_start, vert_end;
1305 
1306  dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1307  dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1308 
1309  val = FLD_VAL(vaccu, vert_start, vert_end) |
1310  FLD_VAL(haccu, hor_start, hor_end);
1311 
1312  dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
1313 }
1314 
1315 static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1316 {
1317  u32 val;
1318  u8 hor_start, hor_end, vert_start, vert_end;
1319 
1320  dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1321  dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1322 
1323  val = FLD_VAL(vaccu, vert_start, vert_end) |
1324  FLD_VAL(haccu, hor_start, hor_end);
1325 
1326  dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
1327 }
1328 
1329 static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu,
1330  int vaccu)
1331 {
1332  u32 val;
1333 
1334  val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1335  dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
1336 }
1337 
1338 static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu,
1339  int vaccu)
1340 {
1341  u32 val;
1342 
1343  val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1344  dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
1345 }
1346 
1347 static void dispc_ovl_set_scale_param(enum omap_plane plane,
1348  u16 orig_width, u16 orig_height,
1349  u16 out_width, u16 out_height,
1350  bool five_taps, u8 rotation,
1351  enum omap_color_component color_comp)
1352 {
1353  int fir_hinc, fir_vinc;
1354 
1355  fir_hinc = 1024 * orig_width / out_width;
1356  fir_vinc = 1024 * orig_height / out_height;
1357 
1358  dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
1359  color_comp);
1360  dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
1361 }
1362 
1363 static void dispc_ovl_set_accu_uv(enum omap_plane plane,
1364  u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
1365  bool ilace, enum omap_color_mode color_mode, u8 rotation)
1366 {
1367  int h_accu2_0, h_accu2_1;
1368  int v_accu2_0, v_accu2_1;
1369  int chroma_hinc, chroma_vinc;
1370  int idx;
1371 
1372  struct accu {
1373  s8 h0_m, h0_n;
1374  s8 h1_m, h1_n;
1375  s8 v0_m, v0_n;
1376  s8 v1_m, v1_n;
1377  };
1378 
1379  const struct accu *accu_table;
1380  const struct accu *accu_val;
1381 
1382  static const struct accu accu_nv12[4] = {
1383  { 0, 1, 0, 1 , -1, 2, 0, 1 },
1384  { 1, 2, -3, 4 , 0, 1, 0, 1 },
1385  { -1, 1, 0, 1 , -1, 2, 0, 1 },
1386  { -1, 2, -1, 2 , -1, 1, 0, 1 },
1387  };
1388 
1389  static const struct accu accu_nv12_ilace[4] = {
1390  { 0, 1, 0, 1 , -3, 4, -1, 4 },
1391  { -1, 4, -3, 4 , 0, 1, 0, 1 },
1392  { -1, 1, 0, 1 , -1, 4, -3, 4 },
1393  { -3, 4, -3, 4 , -1, 1, 0, 1 },
1394  };
1395 
1396  static const struct accu accu_yuv[4] = {
1397  { 0, 1, 0, 1, 0, 1, 0, 1 },
1398  { 0, 1, 0, 1, 0, 1, 0, 1 },
1399  { -1, 1, 0, 1, 0, 1, 0, 1 },
1400  { 0, 1, 0, 1, -1, 1, 0, 1 },
1401  };
1402 
1403  switch (rotation) {
1404  case OMAP_DSS_ROT_0:
1405  idx = 0;
1406  break;
1407  case OMAP_DSS_ROT_90:
1408  idx = 1;
1409  break;
1410  case OMAP_DSS_ROT_180:
1411  idx = 2;
1412  break;
1413  case OMAP_DSS_ROT_270:
1414  idx = 3;
1415  break;
1416  default:
1417  BUG();
1418  return;
1419  }
1420 
1421  switch (color_mode) {
1422  case OMAP_DSS_COLOR_NV12:
1423  if (ilace)
1424  accu_table = accu_nv12_ilace;
1425  else
1426  accu_table = accu_nv12;
1427  break;
1428  case OMAP_DSS_COLOR_YUV2:
1429  case OMAP_DSS_COLOR_UYVY:
1430  accu_table = accu_yuv;
1431  break;
1432  default:
1433  BUG();
1434  return;
1435  }
1436 
1437  accu_val = &accu_table[idx];
1438 
1439  chroma_hinc = 1024 * orig_width / out_width;
1440  chroma_vinc = 1024 * orig_height / out_height;
1441 
1442  h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
1443  h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
1444  v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
1445  v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
1446 
1447  dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
1448  dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
1449 }
1450 
1451 static void dispc_ovl_set_scaling_common(enum omap_plane plane,
1452  u16 orig_width, u16 orig_height,
1453  u16 out_width, u16 out_height,
1454  bool ilace, bool five_taps,
1455  bool fieldmode, enum omap_color_mode color_mode,
1456  u8 rotation)
1457 {
1458  int accu0 = 0;
1459  int accu1 = 0;
1460  u32 l;
1461 
1462  dispc_ovl_set_scale_param(plane, orig_width, orig_height,
1463  out_width, out_height, five_taps,
1464  rotation, DISPC_COLOR_COMPONENT_RGB_Y);
1465  l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1466 
1467  /* RESIZEENABLE and VERTICALTAPS */
1468  l &= ~((0x3 << 5) | (0x1 << 21));
1469  l |= (orig_width != out_width) ? (1 << 5) : 0;
1470  l |= (orig_height != out_height) ? (1 << 6) : 0;
1471  l |= five_taps ? (1 << 21) : 0;
1472 
1473  /* VRESIZECONF and HRESIZECONF */
1475  l &= ~(0x3 << 7);
1476  l |= (orig_width <= out_width) ? 0 : (1 << 7);
1477  l |= (orig_height <= out_height) ? 0 : (1 << 8);
1478  }
1479 
1480  /* LINEBUFFERSPLIT */
1482  l &= ~(0x1 << 22);
1483  l |= five_taps ? (1 << 22) : 0;
1484  }
1485 
1486  dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
1487 
1488  /*
1489  * field 0 = even field = bottom field
1490  * field 1 = odd field = top field
1491  */
1492  if (ilace && !fieldmode) {
1493  accu1 = 0;
1494  accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
1495  if (accu0 >= 1024/2) {
1496  accu1 = 1024/2;
1497  accu0 -= accu1;
1498  }
1499  }
1500 
1501  dispc_ovl_set_vid_accu0(plane, 0, accu0);
1502  dispc_ovl_set_vid_accu1(plane, 0, accu1);
1503 }
1504 
1505 static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
1506  u16 orig_width, u16 orig_height,
1507  u16 out_width, u16 out_height,
1508  bool ilace, bool five_taps,
1509  bool fieldmode, enum omap_color_mode color_mode,
1510  u8 rotation)
1511 {
1512  int scale_x = out_width != orig_width;
1513  int scale_y = out_height != orig_height;
1514  bool chroma_upscale = plane != OMAP_DSS_WB ? true : false;
1515 
1517  return;
1518  if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
1519  color_mode != OMAP_DSS_COLOR_UYVY &&
1520  color_mode != OMAP_DSS_COLOR_NV12)) {
1521  /* reset chroma resampling for RGB formats */
1522  if (plane != OMAP_DSS_WB)
1523  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
1524  return;
1525  }
1526 
1527  dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
1528  out_height, ilace, color_mode, rotation);
1529 
1530  switch (color_mode) {
1531  case OMAP_DSS_COLOR_NV12:
1532  if (chroma_upscale) {
1533  /* UV is subsampled by 2 horizontally and vertically */
1534  orig_height >>= 1;
1535  orig_width >>= 1;
1536  } else {
1537  /* UV is downsampled by 2 horizontally and vertically */
1538  orig_height <<= 1;
1539  orig_width <<= 1;
1540  }
1541 
1542  break;
1543  case OMAP_DSS_COLOR_YUV2:
1544  case OMAP_DSS_COLOR_UYVY:
1545  /* For YUV422 with 90/270 rotation, we don't upsample chroma */
1546  if (rotation == OMAP_DSS_ROT_0 ||
1547  rotation == OMAP_DSS_ROT_180) {
1548  if (chroma_upscale)
1549  /* UV is subsampled by 2 horizontally */
1550  orig_width >>= 1;
1551  else
1552  /* UV is downsampled by 2 horizontally */
1553  orig_width <<= 1;
1554  }
1555 
1556  /* must use FIR for YUV422 if rotated */
1557  if (rotation != OMAP_DSS_ROT_0)
1558  scale_x = scale_y = true;
1559 
1560  break;
1561  default:
1562  BUG();
1563  return;
1564  }
1565 
1566  if (out_width != orig_width)
1567  scale_x = true;
1568  if (out_height != orig_height)
1569  scale_y = true;
1570 
1571  dispc_ovl_set_scale_param(plane, orig_width, orig_height,
1572  out_width, out_height, five_taps,
1573  rotation, DISPC_COLOR_COMPONENT_UV);
1574 
1575  if (plane != OMAP_DSS_WB)
1577  (scale_x || scale_y) ? 1 : 0, 8, 8);
1578 
1579  /* set H scaling */
1580  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
1581  /* set V scaling */
1582  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
1583 }
1584 
1585 static void dispc_ovl_set_scaling(enum omap_plane plane,
1586  u16 orig_width, u16 orig_height,
1587  u16 out_width, u16 out_height,
1588  bool ilace, bool five_taps,
1589  bool fieldmode, enum omap_color_mode color_mode,
1590  u8 rotation)
1591 {
1592  BUG_ON(plane == OMAP_DSS_GFX);
1593 
1594  dispc_ovl_set_scaling_common(plane,
1595  orig_width, orig_height,
1596  out_width, out_height,
1597  ilace, five_taps,
1598  fieldmode, color_mode,
1599  rotation);
1600 
1601  dispc_ovl_set_scaling_uv(plane,
1602  orig_width, orig_height,
1603  out_width, out_height,
1604  ilace, five_taps,
1605  fieldmode, color_mode,
1606  rotation);
1607 }
1608 
1609 static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1610  bool mirroring, enum omap_color_mode color_mode)
1611 {
1612  bool row_repeat = false;
1613  int vidrot = 0;
1614 
1615  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1616  color_mode == OMAP_DSS_COLOR_UYVY) {
1617 
1618  if (mirroring) {
1619  switch (rotation) {
1620  case OMAP_DSS_ROT_0:
1621  vidrot = 2;
1622  break;
1623  case OMAP_DSS_ROT_90:
1624  vidrot = 1;
1625  break;
1626  case OMAP_DSS_ROT_180:
1627  vidrot = 0;
1628  break;
1629  case OMAP_DSS_ROT_270:
1630  vidrot = 3;
1631  break;
1632  }
1633  } else {
1634  switch (rotation) {
1635  case OMAP_DSS_ROT_0:
1636  vidrot = 0;
1637  break;
1638  case OMAP_DSS_ROT_90:
1639  vidrot = 1;
1640  break;
1641  case OMAP_DSS_ROT_180:
1642  vidrot = 2;
1643  break;
1644  case OMAP_DSS_ROT_270:
1645  vidrot = 3;
1646  break;
1647  }
1648  }
1649 
1650  if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1651  row_repeat = true;
1652  else
1653  row_repeat = false;
1654  }
1655 
1656  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
1659  row_repeat ? 1 : 0, 18, 18);
1660 }
1661 
1662 static int color_mode_to_bpp(enum omap_color_mode color_mode)
1663 {
1664  switch (color_mode) {
1665  case OMAP_DSS_COLOR_CLUT1:
1666  return 1;
1667  case OMAP_DSS_COLOR_CLUT2:
1668  return 2;
1669  case OMAP_DSS_COLOR_CLUT4:
1670  return 4;
1671  case OMAP_DSS_COLOR_CLUT8:
1672  case OMAP_DSS_COLOR_NV12:
1673  return 8;
1674  case OMAP_DSS_COLOR_RGB12U:
1675  case OMAP_DSS_COLOR_RGB16:
1676  case OMAP_DSS_COLOR_ARGB16:
1677  case OMAP_DSS_COLOR_YUV2:
1678  case OMAP_DSS_COLOR_UYVY:
1679  case OMAP_DSS_COLOR_RGBA16:
1680  case OMAP_DSS_COLOR_RGBX16:
1683  return 16;
1684  case OMAP_DSS_COLOR_RGB24P:
1685  return 24;
1686  case OMAP_DSS_COLOR_RGB24U:
1687  case OMAP_DSS_COLOR_ARGB32:
1688  case OMAP_DSS_COLOR_RGBA32:
1689  case OMAP_DSS_COLOR_RGBX32:
1690  return 32;
1691  default:
1692  BUG();
1693  return 0;
1694  }
1695 }
1696 
1697 static s32 pixinc(int pixels, u8 ps)
1698 {
1699  if (pixels == 1)
1700  return 1;
1701  else if (pixels > 1)
1702  return 1 + (pixels - 1) * ps;
1703  else if (pixels < 0)
1704  return 1 - (-pixels + 1) * ps;
1705  else
1706  BUG();
1707  return 0;
1708 }
1709 
1710 static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1711  u16 screen_width,
1712  u16 width, u16 height,
1713  enum omap_color_mode color_mode, bool fieldmode,
1714  unsigned int field_offset,
1715  unsigned *offset0, unsigned *offset1,
1716  s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1717 {
1718  u8 ps;
1719 
1720  /* FIXME CLUT formats */
1721  switch (color_mode) {
1722  case OMAP_DSS_COLOR_CLUT1:
1723  case OMAP_DSS_COLOR_CLUT2:
1724  case OMAP_DSS_COLOR_CLUT4:
1725  case OMAP_DSS_COLOR_CLUT8:
1726  BUG();
1727  return;
1728  case OMAP_DSS_COLOR_YUV2:
1729  case OMAP_DSS_COLOR_UYVY:
1730  ps = 4;
1731  break;
1732  default:
1733  ps = color_mode_to_bpp(color_mode) / 8;
1734  break;
1735  }
1736 
1737  DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1738  width, height);
1739 
1740  /*
1741  * field 0 = even field = bottom field
1742  * field 1 = odd field = top field
1743  */
1744  switch (rotation + mirror * 4) {
1745  case OMAP_DSS_ROT_0:
1746  case OMAP_DSS_ROT_180:
1747  /*
1748  * If the pixel format is YUV or UYVY divide the width
1749  * of the image by 2 for 0 and 180 degree rotation.
1750  */
1751  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1752  color_mode == OMAP_DSS_COLOR_UYVY)
1753  width = width >> 1;
1754  case OMAP_DSS_ROT_90:
1755  case OMAP_DSS_ROT_270:
1756  *offset1 = 0;
1757  if (field_offset)
1758  *offset0 = field_offset * screen_width * ps;
1759  else
1760  *offset0 = 0;
1761 
1762  *row_inc = pixinc(1 +
1763  (y_predecim * screen_width - x_predecim * width) +
1764  (fieldmode ? screen_width : 0), ps);
1765  *pix_inc = pixinc(x_predecim, ps);
1766  break;
1767 
1768  case OMAP_DSS_ROT_0 + 4:
1769  case OMAP_DSS_ROT_180 + 4:
1770  /* If the pixel format is YUV or UYVY divide the width
1771  * of the image by 2 for 0 degree and 180 degree
1772  */
1773  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1774  color_mode == OMAP_DSS_COLOR_UYVY)
1775  width = width >> 1;
1776  case OMAP_DSS_ROT_90 + 4:
1777  case OMAP_DSS_ROT_270 + 4:
1778  *offset1 = 0;
1779  if (field_offset)
1780  *offset0 = field_offset * screen_width * ps;
1781  else
1782  *offset0 = 0;
1783  *row_inc = pixinc(1 -
1784  (y_predecim * screen_width + x_predecim * width) -
1785  (fieldmode ? screen_width : 0), ps);
1786  *pix_inc = pixinc(x_predecim, ps);
1787  break;
1788 
1789  default:
1790  BUG();
1791  return;
1792  }
1793 }
1794 
1795 static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1796  u16 screen_width,
1797  u16 width, u16 height,
1798  enum omap_color_mode color_mode, bool fieldmode,
1799  unsigned int field_offset,
1800  unsigned *offset0, unsigned *offset1,
1801  s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1802 {
1803  u8 ps;
1804  u16 fbw, fbh;
1805 
1806  /* FIXME CLUT formats */
1807  switch (color_mode) {
1808  case OMAP_DSS_COLOR_CLUT1:
1809  case OMAP_DSS_COLOR_CLUT2:
1810  case OMAP_DSS_COLOR_CLUT4:
1811  case OMAP_DSS_COLOR_CLUT8:
1812  BUG();
1813  return;
1814  default:
1815  ps = color_mode_to_bpp(color_mode) / 8;
1816  break;
1817  }
1818 
1819  DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1820  width, height);
1821 
1822  /* width & height are overlay sizes, convert to fb sizes */
1823 
1824  if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1825  fbw = width;
1826  fbh = height;
1827  } else {
1828  fbw = height;
1829  fbh = width;
1830  }
1831 
1832  /*
1833  * field 0 = even field = bottom field
1834  * field 1 = odd field = top field
1835  */
1836  switch (rotation + mirror * 4) {
1837  case OMAP_DSS_ROT_0:
1838  *offset1 = 0;
1839  if (field_offset)
1840  *offset0 = *offset1 + field_offset * screen_width * ps;
1841  else
1842  *offset0 = *offset1;
1843  *row_inc = pixinc(1 +
1844  (y_predecim * screen_width - fbw * x_predecim) +
1845  (fieldmode ? screen_width : 0), ps);
1846  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1847  color_mode == OMAP_DSS_COLOR_UYVY)
1848  *pix_inc = pixinc(x_predecim, 2 * ps);
1849  else
1850  *pix_inc = pixinc(x_predecim, ps);
1851  break;
1852  case OMAP_DSS_ROT_90:
1853  *offset1 = screen_width * (fbh - 1) * ps;
1854  if (field_offset)
1855  *offset0 = *offset1 + field_offset * ps;
1856  else
1857  *offset0 = *offset1;
1858  *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) +
1859  y_predecim + (fieldmode ? 1 : 0), ps);
1860  *pix_inc = pixinc(-x_predecim * screen_width, ps);
1861  break;
1862  case OMAP_DSS_ROT_180:
1863  *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1864  if (field_offset)
1865  *offset0 = *offset1 - field_offset * screen_width * ps;
1866  else
1867  *offset0 = *offset1;
1868  *row_inc = pixinc(-1 -
1869  (y_predecim * screen_width - fbw * x_predecim) -
1870  (fieldmode ? screen_width : 0), ps);
1871  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1872  color_mode == OMAP_DSS_COLOR_UYVY)
1873  *pix_inc = pixinc(-x_predecim, 2 * ps);
1874  else
1875  *pix_inc = pixinc(-x_predecim, ps);
1876  break;
1877  case OMAP_DSS_ROT_270:
1878  *offset1 = (fbw - 1) * ps;
1879  if (field_offset)
1880  *offset0 = *offset1 - field_offset * ps;
1881  else
1882  *offset0 = *offset1;
1883  *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) -
1884  y_predecim - (fieldmode ? 1 : 0), ps);
1885  *pix_inc = pixinc(x_predecim * screen_width, ps);
1886  break;
1887 
1888  /* mirroring */
1889  case OMAP_DSS_ROT_0 + 4:
1890  *offset1 = (fbw - 1) * ps;
1891  if (field_offset)
1892  *offset0 = *offset1 + field_offset * screen_width * ps;
1893  else
1894  *offset0 = *offset1;
1895  *row_inc = pixinc(y_predecim * screen_width * 2 - 1 +
1896  (fieldmode ? screen_width : 0),
1897  ps);
1898  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1899  color_mode == OMAP_DSS_COLOR_UYVY)
1900  *pix_inc = pixinc(-x_predecim, 2 * ps);
1901  else
1902  *pix_inc = pixinc(-x_predecim, ps);
1903  break;
1904 
1905  case OMAP_DSS_ROT_90 + 4:
1906  *offset1 = 0;
1907  if (field_offset)
1908  *offset0 = *offset1 + field_offset * ps;
1909  else
1910  *offset0 = *offset1;
1911  *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) +
1912  y_predecim + (fieldmode ? 1 : 0),
1913  ps);
1914  *pix_inc = pixinc(x_predecim * screen_width, ps);
1915  break;
1916 
1917  case OMAP_DSS_ROT_180 + 4:
1918  *offset1 = screen_width * (fbh - 1) * ps;
1919  if (field_offset)
1920  *offset0 = *offset1 - field_offset * screen_width * ps;
1921  else
1922  *offset0 = *offset1;
1923  *row_inc = pixinc(1 - y_predecim * screen_width * 2 -
1924  (fieldmode ? screen_width : 0),
1925  ps);
1926  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1927  color_mode == OMAP_DSS_COLOR_UYVY)
1928  *pix_inc = pixinc(x_predecim, 2 * ps);
1929  else
1930  *pix_inc = pixinc(x_predecim, ps);
1931  break;
1932 
1933  case OMAP_DSS_ROT_270 + 4:
1934  *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1935  if (field_offset)
1936  *offset0 = *offset1 - field_offset * ps;
1937  else
1938  *offset0 = *offset1;
1939  *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) -
1940  y_predecim - (fieldmode ? 1 : 0),
1941  ps);
1942  *pix_inc = pixinc(-x_predecim * screen_width, ps);
1943  break;
1944 
1945  default:
1946  BUG();
1947  return;
1948  }
1949 }
1950 
1951 static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
1952  enum omap_color_mode color_mode, bool fieldmode,
1953  unsigned int field_offset, unsigned *offset0, unsigned *offset1,
1954  s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1955 {
1956  u8 ps;
1957 
1958  switch (color_mode) {
1959  case OMAP_DSS_COLOR_CLUT1:
1960  case OMAP_DSS_COLOR_CLUT2:
1961  case OMAP_DSS_COLOR_CLUT4:
1962  case OMAP_DSS_COLOR_CLUT8:
1963  BUG();
1964  return;
1965  default:
1966  ps = color_mode_to_bpp(color_mode) / 8;
1967  break;
1968  }
1969 
1970  DSSDBG("scrw %d, width %d\n", screen_width, width);
1971 
1972  /*
1973  * field 0 = even field = bottom field
1974  * field 1 = odd field = top field
1975  */
1976  *offset1 = 0;
1977  if (field_offset)
1978  *offset0 = *offset1 + field_offset * screen_width * ps;
1979  else
1980  *offset0 = *offset1;
1981  *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
1982  (fieldmode ? screen_width : 0), ps);
1983  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1984  color_mode == OMAP_DSS_COLOR_UYVY)
1985  *pix_inc = pixinc(x_predecim, 2 * ps);
1986  else
1987  *pix_inc = pixinc(x_predecim, ps);
1988 }
1989 
1990 /*
1991  * This function is used to avoid synclosts in OMAP3, because of some
1992  * undocumented horizontal position and timing related limitations.
1993  */
1994 static int check_horiz_timing_omap3(enum omap_plane plane,
1995  const struct omap_video_timings *t, u16 pos_x,
1996  u16 width, u16 height, u16 out_width, u16 out_height)
1997 {
1998  int DS = DIV_ROUND_UP(height, out_height);
1999  unsigned long nonactive;
2000  static const u8 limits[3] = { 8, 10, 20 };
2001  u64 val, blank;
2002  unsigned long pclk = dispc_plane_pclk_rate(plane);
2003  unsigned long lclk = dispc_plane_lclk_rate(plane);
2004  int i;
2005 
2006  nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
2007 
2008  i = 0;
2009  if (out_height < height)
2010  i++;
2011  if (out_width < width)
2012  i++;
2013  blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk);
2014  DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
2015  if (blank <= limits[i])
2016  return -EINVAL;
2017 
2018  /*
2019  * Pixel data should be prepared before visible display point starts.
2020  * So, atleast DS-2 lines must have already been fetched by DISPC
2021  * during nonactive - pos_x period.
2022  */
2023  val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
2024  DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
2025  val, max(0, DS - 2) * width);
2026  if (val < max(0, DS - 2) * width)
2027  return -EINVAL;
2028 
2029  /*
2030  * All lines need to be refilled during the nonactive period of which
2031  * only one line can be loaded during the active period. So, atleast
2032  * DS - 1 lines should be loaded during nonactive period.
2033  */
2034  val = div_u64((u64)nonactive * lclk, pclk);
2035  DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
2036  val, max(0, DS - 1) * width);
2037  if (val < max(0, DS - 1) * width)
2038  return -EINVAL;
2039 
2040  return 0;
2041 }
2042 
2043 static unsigned long calc_core_clk_five_taps(enum omap_plane plane,
2044  const struct omap_video_timings *mgr_timings, u16 width,
2045  u16 height, u16 out_width, u16 out_height,
2046  enum omap_color_mode color_mode)
2047 {
2048  u32 core_clk = 0;
2049  u64 tmp;
2050  unsigned long pclk = dispc_plane_pclk_rate(plane);
2051 
2052  if (height <= out_height && width <= out_width)
2053  return (unsigned long) pclk;
2054 
2055  if (height > out_height) {
2056  unsigned int ppl = mgr_timings->x_res;
2057 
2058  tmp = pclk * height * out_width;
2059  do_div(tmp, 2 * out_height * ppl);
2060  core_clk = tmp;
2061 
2062  if (height > 2 * out_height) {
2063  if (ppl == out_width)
2064  return 0;
2065 
2066  tmp = pclk * (height - 2 * out_height) * out_width;
2067  do_div(tmp, 2 * out_height * (ppl - out_width));
2068  core_clk = max_t(u32, core_clk, tmp);
2069  }
2070  }
2071 
2072  if (width > out_width) {
2073  tmp = pclk * width;
2074  do_div(tmp, out_width);
2075  core_clk = max_t(u32, core_clk, tmp);
2076 
2077  if (color_mode == OMAP_DSS_COLOR_RGB24U)
2078  core_clk <<= 1;
2079  }
2080 
2081  return core_clk;
2082 }
2083 
2084 static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width,
2085  u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2086 {
2087  unsigned long pclk = dispc_plane_pclk_rate(plane);
2088 
2089  if (height > out_height && width > out_width)
2090  return pclk * 4;
2091  else
2092  return pclk * 2;
2093 }
2094 
2095 static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width,
2096  u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2097 {
2098  unsigned int hf, vf;
2099  unsigned long pclk = dispc_plane_pclk_rate(plane);
2100 
2101  /*
2102  * FIXME how to determine the 'A' factor
2103  * for the no downscaling case ?
2104  */
2105 
2106  if (width > 3 * out_width)
2107  hf = 4;
2108  else if (width > 2 * out_width)
2109  hf = 3;
2110  else if (width > out_width)
2111  hf = 2;
2112  else
2113  hf = 1;
2114  if (height > out_height)
2115  vf = 2;
2116  else
2117  vf = 1;
2118 
2119  return pclk * vf * hf;
2120 }
2121 
2122 static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width,
2123  u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2124 {
2125  unsigned long pclk;
2126 
2127  /*
2128  * If the overlay/writeback is in mem to mem mode, there are no
2129  * downscaling limitations with respect to pixel clock, return 1 as
2130  * required core clock to represent that we have sufficient enough
2131  * core clock to do maximum downscaling
2132  */
2133  if (mem_to_mem)
2134  return 1;
2135 
2136  pclk = dispc_plane_pclk_rate(plane);
2137 
2138  if (width > out_width)
2139  return DIV_ROUND_UP(pclk, out_width) * width;
2140  else
2141  return pclk;
2142 }
2143 
2144 static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane,
2145  const struct omap_video_timings *mgr_timings,
2146  u16 width, u16 height, u16 out_width, u16 out_height,
2147  enum omap_color_mode color_mode, bool *five_taps,
2148  int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2149  u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2150 {
2151  int error;
2152  u16 in_width, in_height;
2153  int min_factor = min(*decim_x, *decim_y);
2154  const int maxsinglelinewidth =
2156 
2157  *five_taps = false;
2158 
2159  do {
2160  in_height = DIV_ROUND_UP(height, *decim_y);
2161  in_width = DIV_ROUND_UP(width, *decim_x);
2162  *core_clk = dispc.feat->calc_core_clk(plane, in_width,
2163  in_height, out_width, out_height, mem_to_mem);
2164  error = (in_width > maxsinglelinewidth || !*core_clk ||
2165  *core_clk > dispc_core_clk_rate());
2166  if (error) {
2167  if (*decim_x == *decim_y) {
2168  *decim_x = min_factor;
2169  ++*decim_y;
2170  } else {
2171  swap(*decim_x, *decim_y);
2172  if (*decim_x < *decim_y)
2173  ++*decim_x;
2174  }
2175  }
2176  } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2177 
2178  if (in_width > maxsinglelinewidth) {
2179  DSSERR("Cannot scale max input width exceeded");
2180  return -EINVAL;
2181  }
2182  return 0;
2183 }
2184 
2185 static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
2186  const struct omap_video_timings *mgr_timings,
2187  u16 width, u16 height, u16 out_width, u16 out_height,
2188  enum omap_color_mode color_mode, bool *five_taps,
2189  int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2190  u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2191 {
2192  int error;
2193  u16 in_width, in_height;
2194  int min_factor = min(*decim_x, *decim_y);
2195  const int maxsinglelinewidth =
2197 
2198  do {
2199  in_height = DIV_ROUND_UP(height, *decim_y);
2200  in_width = DIV_ROUND_UP(width, *decim_x);
2201  *core_clk = calc_core_clk_five_taps(plane, mgr_timings,
2202  in_width, in_height, out_width, out_height, color_mode);
2203 
2204  error = check_horiz_timing_omap3(plane, mgr_timings,
2205  pos_x, in_width, in_height, out_width,
2206  out_height);
2207 
2208  if (in_width > maxsinglelinewidth)
2209  if (in_height > out_height &&
2210  in_height < out_height * 2)
2211  *five_taps = false;
2212  if (!*five_taps)
2213  *core_clk = dispc.feat->calc_core_clk(plane, in_width,
2214  in_height, out_width, out_height,
2215  mem_to_mem);
2216 
2217  error = (error || in_width > maxsinglelinewidth * 2 ||
2218  (in_width > maxsinglelinewidth && *five_taps) ||
2219  !*core_clk || *core_clk > dispc_core_clk_rate());
2220  if (error) {
2221  if (*decim_x == *decim_y) {
2222  *decim_x = min_factor;
2223  ++*decim_y;
2224  } else {
2225  swap(*decim_x, *decim_y);
2226  if (*decim_x < *decim_y)
2227  ++*decim_x;
2228  }
2229  }
2230  } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2231 
2232  if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height,
2233  out_width, out_height)){
2234  DSSERR("horizontal timing too tight\n");
2235  return -EINVAL;
2236  }
2237 
2238  if (in_width > (maxsinglelinewidth * 2)) {
2239  DSSERR("Cannot setup scaling");
2240  DSSERR("width exceeds maximum width possible");
2241  return -EINVAL;
2242  }
2243 
2244  if (in_width > maxsinglelinewidth && *five_taps) {
2245  DSSERR("cannot setup scaling with five taps");
2246  return -EINVAL;
2247  }
2248  return 0;
2249 }
2250 
2251 static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane,
2252  const struct omap_video_timings *mgr_timings,
2253  u16 width, u16 height, u16 out_width, u16 out_height,
2254  enum omap_color_mode color_mode, bool *five_taps,
2255  int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2256  u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2257 {
2258  u16 in_width, in_width_max;
2259  int decim_x_min = *decim_x;
2260  u16 in_height = DIV_ROUND_UP(height, *decim_y);
2261  const int maxsinglelinewidth =
2263  unsigned long pclk = dispc_plane_pclk_rate(plane);
2264  const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
2265 
2266  if (mem_to_mem)
2267  in_width_max = DIV_ROUND_UP(out_width, maxdownscale);
2268  else
2269  in_width_max = dispc_core_clk_rate() /
2270  DIV_ROUND_UP(pclk, out_width);
2271 
2272  *decim_x = DIV_ROUND_UP(width, in_width_max);
2273 
2274  *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
2275  if (*decim_x > *x_predecim)
2276  return -EINVAL;
2277 
2278  do {
2279  in_width = DIV_ROUND_UP(width, *decim_x);
2280  } while (*decim_x <= *x_predecim &&
2281  in_width > maxsinglelinewidth && ++*decim_x);
2282 
2283  if (in_width > maxsinglelinewidth) {
2284  DSSERR("Cannot scale width exceeds max line width");
2285  return -EINVAL;
2286  }
2287 
2288  *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height,
2289  out_width, out_height, mem_to_mem);
2290  return 0;
2291 }
2292 
2293 static int dispc_ovl_calc_scaling(enum omap_plane plane,
2294  enum omap_overlay_caps caps,
2295  const struct omap_video_timings *mgr_timings,
2296  u16 width, u16 height, u16 out_width, u16 out_height,
2297  enum omap_color_mode color_mode, bool *five_taps,
2298  int *x_predecim, int *y_predecim, u16 pos_x,
2299  enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
2300 {
2301  const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
2302  const int max_decim_limit = 16;
2303  unsigned long core_clk = 0;
2304  int decim_x, decim_y, ret;
2305 
2306  if (width == out_width && height == out_height)
2307  return 0;
2308 
2309  if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
2310  return -EINVAL;
2311 
2312  *x_predecim = max_decim_limit;
2313  *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
2314  dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit;
2315 
2316  if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
2317  color_mode == OMAP_DSS_COLOR_CLUT2 ||
2318  color_mode == OMAP_DSS_COLOR_CLUT4 ||
2319  color_mode == OMAP_DSS_COLOR_CLUT8) {
2320  *x_predecim = 1;
2321  *y_predecim = 1;
2322  *five_taps = false;
2323  return 0;
2324  }
2325 
2326  decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
2327  decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
2328 
2329  if (decim_x > *x_predecim || out_width > width * 8)
2330  return -EINVAL;
2331 
2332  if (decim_y > *y_predecim || out_height > height * 8)
2333  return -EINVAL;
2334 
2335  ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height,
2336  out_width, out_height, color_mode, five_taps,
2337  x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
2338  mem_to_mem);
2339  if (ret)
2340  return ret;
2341 
2342  DSSDBG("required core clk rate = %lu Hz\n", core_clk);
2343  DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
2344 
2345  if (!core_clk || core_clk > dispc_core_clk_rate()) {
2346  DSSERR("failed to set up scaling, "
2347  "required core clk rate = %lu Hz, "
2348  "current core clk rate = %lu Hz\n",
2349  core_clk, dispc_core_clk_rate());
2350  return -EINVAL;
2351  }
2352 
2353  *x_predecim = decim_x;
2354  *y_predecim = decim_y;
2355  return 0;
2356 }
2357 
2358 static int dispc_ovl_setup_common(enum omap_plane plane,
2359  enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
2360  u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
2361  u16 out_width, u16 out_height, enum omap_color_mode color_mode,
2362  u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha,
2363  u8 global_alpha, enum omap_dss_rotation_type rotation_type,
2364  bool replication, const struct omap_video_timings *mgr_timings,
2365  bool mem_to_mem)
2366 {
2367  bool five_taps = true;
2368  bool fieldmode = 0;
2369  int r, cconv = 0;
2370  unsigned offset0, offset1;
2371  s32 row_inc;
2372  s32 pix_inc;
2373  u16 frame_height = height;
2374  unsigned int field_offset = 0;
2375  u16 in_height = height;
2376  u16 in_width = width;
2377  int x_predecim = 1, y_predecim = 1;
2378  bool ilace = mgr_timings->interlace;
2379 
2380  if (paddr == 0)
2381  return -EINVAL;
2382 
2383  out_width = out_width == 0 ? width : out_width;
2384  out_height = out_height == 0 ? height : out_height;
2385 
2386  if (ilace && height == out_height)
2387  fieldmode = 1;
2388 
2389  if (ilace) {
2390  if (fieldmode)
2391  in_height /= 2;
2392  pos_y /= 2;
2393  out_height /= 2;
2394 
2395  DSSDBG("adjusting for ilace: height %d, pos_y %d, "
2396  "out_height %d\n", in_height, pos_y,
2397  out_height);
2398  }
2399 
2400  if (!dss_feat_color_mode_supported(plane, color_mode))
2401  return -EINVAL;
2402 
2403  r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width,
2404  in_height, out_width, out_height, color_mode,
2405  &five_taps, &x_predecim, &y_predecim, pos_x,
2406  rotation_type, mem_to_mem);
2407  if (r)
2408  return r;
2409 
2410  in_width = DIV_ROUND_UP(in_width, x_predecim);
2411  in_height = DIV_ROUND_UP(in_height, y_predecim);
2412 
2413  if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2414  color_mode == OMAP_DSS_COLOR_UYVY ||
2415  color_mode == OMAP_DSS_COLOR_NV12)
2416  cconv = 1;
2417 
2418  if (ilace && !fieldmode) {
2419  /*
2420  * when downscaling the bottom field may have to start several
2421  * source lines below the top field. Unfortunately ACCUI
2422  * registers will only hold the fractional part of the offset
2423  * so the integer part must be added to the base address of the
2424  * bottom field.
2425  */
2426  if (!in_height || in_height == out_height)
2427  field_offset = 0;
2428  else
2429  field_offset = in_height / out_height / 2;
2430  }
2431 
2432  /* Fields are independent but interleaved in memory. */
2433  if (fieldmode)
2434  field_offset = 1;
2435 
2436  offset0 = 0;
2437  offset1 = 0;
2438  row_inc = 0;
2439  pix_inc = 0;
2440 
2441  if (rotation_type == OMAP_DSS_ROT_TILER)
2442  calc_tiler_rotation_offset(screen_width, in_width,
2443  color_mode, fieldmode, field_offset,
2444  &offset0, &offset1, &row_inc, &pix_inc,
2445  x_predecim, y_predecim);
2446  else if (rotation_type == OMAP_DSS_ROT_DMA)
2447  calc_dma_rotation_offset(rotation, mirror,
2448  screen_width, in_width, frame_height,
2449  color_mode, fieldmode, field_offset,
2450  &offset0, &offset1, &row_inc, &pix_inc,
2451  x_predecim, y_predecim);
2452  else
2453  calc_vrfb_rotation_offset(rotation, mirror,
2454  screen_width, in_width, frame_height,
2455  color_mode, fieldmode, field_offset,
2456  &offset0, &offset1, &row_inc, &pix_inc,
2457  x_predecim, y_predecim);
2458 
2459  DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
2460  offset0, offset1, row_inc, pix_inc);
2461 
2462  dispc_ovl_set_color_mode(plane, color_mode);
2463 
2464  dispc_ovl_configure_burst_type(plane, rotation_type);
2465 
2466  dispc_ovl_set_ba0(plane, paddr + offset0);
2467  dispc_ovl_set_ba1(plane, paddr + offset1);
2468 
2469  if (OMAP_DSS_COLOR_NV12 == color_mode) {
2470  dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
2471  dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
2472  }
2473 
2474  dispc_ovl_set_row_inc(plane, row_inc);
2475  dispc_ovl_set_pix_inc(plane, pix_inc);
2476 
2477  DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
2478  in_height, out_width, out_height);
2479 
2480  dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
2481 
2482  dispc_ovl_set_input_size(plane, in_width, in_height);
2483 
2484  if (caps & OMAP_DSS_OVL_CAP_SCALE) {
2485  dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
2486  out_height, ilace, five_taps, fieldmode,
2487  color_mode, rotation);
2488  dispc_ovl_set_output_size(plane, out_width, out_height);
2489  dispc_ovl_set_vid_color_conv(plane, cconv);
2490  }
2491 
2492  dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode);
2493 
2494  dispc_ovl_set_zorder(plane, caps, zorder);
2495  dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
2496  dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
2497 
2498  dispc_ovl_enable_replication(plane, caps, replication);
2499 
2500  return 0;
2501 }
2502 
2503 int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
2504  bool replication, const struct omap_video_timings *mgr_timings,
2505  bool mem_to_mem)
2506 {
2507  int r;
2508  struct omap_overlay *ovl = omap_dss_get_overlay(plane);
2509  enum omap_channel channel;
2510 
2511  channel = dispc_ovl_get_channel_out(plane);
2512 
2513  DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
2514  "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
2515  plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x,
2516  oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
2517  oi->color_mode, oi->rotation, oi->mirror, channel, replication);
2518 
2519  r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr,
2520  oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
2521  oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
2522  oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
2523  oi->rotation_type, replication, mgr_timings, mem_to_mem);
2524 
2525  return r;
2526 }
2527 
2529  bool mem_to_mem, const struct omap_video_timings *mgr_timings)
2530 {
2531  int r;
2532  u32 l;
2533  enum omap_plane plane = OMAP_DSS_WB;
2534  const int pos_x = 0, pos_y = 0;
2535  const u8 zorder = 0, global_alpha = 0;
2536  const bool replication = false;
2537  bool truncation;
2538  int in_width = mgr_timings->x_res;
2539  int in_height = mgr_timings->y_res;
2540  enum omap_overlay_caps caps =
2541  OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
2542 
2543  DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
2544  "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width,
2545  in_height, wi->width, wi->height, wi->color_mode, wi->rotation,
2546  wi->mirror);
2547 
2548  r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
2549  wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
2550  wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder,
2551  wi->pre_mult_alpha, global_alpha, wi->rotation_type,
2552  replication, mgr_timings, mem_to_mem);
2553 
2554  switch (wi->color_mode) {
2555  case OMAP_DSS_COLOR_RGB16:
2556  case OMAP_DSS_COLOR_RGB24P:
2557  case OMAP_DSS_COLOR_ARGB16:
2558  case OMAP_DSS_COLOR_RGBA16:
2559  case OMAP_DSS_COLOR_RGB12U:
2562  case OMAP_DSS_COLOR_RGBX16:
2563  truncation = true;
2564  break;
2565  default:
2566  truncation = false;
2567  break;
2568  }
2569 
2570  /* setup extra DISPC_WB_ATTRIBUTES */
2571  l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
2572  l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
2573  l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
2574  dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
2575 
2576  return r;
2577 }
2578 
2579 int dispc_ovl_enable(enum omap_plane plane, bool enable)
2580 {
2581  DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
2582 
2583  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
2584 
2585  return 0;
2586 }
2587 
2588 static void dispc_disable_isr(void *data, u32 mask)
2589 {
2590  struct completion *compl = data;
2591  complete(compl);
2592 }
2593 
2594 static void _enable_lcd_out(enum omap_channel channel, bool enable)
2595 {
2596  mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
2597  /* flush posted write */
2598  mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2599 }
2600 
2601 static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable)
2602 {
2603  struct completion frame_done_completion;
2604  bool is_on;
2605  int r;
2606  u32 irq;
2607 
2608  /* When we disable LCD output, we need to wait until frame is done.
2609  * Otherwise the DSS is still working, and turning off the clocks
2610  * prevents DSS from going to OFF mode */
2611  is_on = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2612 
2613  irq = mgr_desc[channel].framedone_irq;
2614 
2615  if (!enable && is_on) {
2616  init_completion(&frame_done_completion);
2617 
2618  r = omap_dispc_register_isr(dispc_disable_isr,
2619  &frame_done_completion, irq);
2620 
2621  if (r)
2622  DSSERR("failed to register FRAMEDONE isr\n");
2623  }
2624 
2625  _enable_lcd_out(channel, enable);
2626 
2627  if (!enable && is_on) {
2628  if (!wait_for_completion_timeout(&frame_done_completion,
2629  msecs_to_jiffies(100)))
2630  DSSERR("timeout waiting for FRAME DONE\n");
2631 
2632  r = omap_dispc_unregister_isr(dispc_disable_isr,
2633  &frame_done_completion, irq);
2634 
2635  if (r)
2636  DSSERR("failed to unregister FRAMEDONE isr\n");
2637  }
2638 }
2639 
2640 static void _enable_digit_out(bool enable)
2641 {
2642  REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
2643  /* flush posted write */
2644  dispc_read_reg(DISPC_CONTROL);
2645 }
2646 
2647 static void dispc_mgr_enable_digit_out(bool enable)
2648 {
2649  struct completion frame_done_completion;
2651  int r, i;
2652  u32 irq_mask;
2653  int num_irqs;
2654 
2655  if (REG_GET(DISPC_CONTROL, 1, 1) == enable)
2656  return;
2657 
2659 
2660  if (enable) {
2661  unsigned long flags;
2662  /* When we enable digit output, we'll get an extra digit
2663  * sync lost interrupt, that we need to ignore */
2664  spin_lock_irqsave(&dispc.irq_lock, flags);
2665  dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
2666  _omap_dispc_set_irqs();
2667  spin_unlock_irqrestore(&dispc.irq_lock, flags);
2668  }
2669 
2670  /* When we disable digit output, we need to wait until fields are done.
2671  * Otherwise the DSS is still working, and turning off the clocks
2672  * prevents DSS from going to OFF mode. And when enabling, we need to
2673  * wait for the extra sync losts */
2674  init_completion(&frame_done_completion);
2675 
2676  if (src == DSS_HDMI_M_PCLK && enable == false) {
2677  irq_mask = DISPC_IRQ_FRAMEDONETV;
2678  num_irqs = 1;
2679  } else {
2681  /* XXX I understand from TRM that we should only wait for the
2682  * current field to complete. But it seems we have to wait for
2683  * both fields */
2684  num_irqs = 2;
2685  }
2686 
2687  r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
2688  irq_mask);
2689  if (r)
2690  DSSERR("failed to register %x isr\n", irq_mask);
2691 
2692  _enable_digit_out(enable);
2693 
2694  for (i = 0; i < num_irqs; ++i) {
2695  if (!wait_for_completion_timeout(&frame_done_completion,
2696  msecs_to_jiffies(100)))
2697  DSSERR("timeout waiting for digit out to %s\n",
2698  enable ? "start" : "stop");
2699  }
2700 
2701  r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion,
2702  irq_mask);
2703  if (r)
2704  DSSERR("failed to unregister %x isr\n", irq_mask);
2705 
2706  if (enable) {
2707  unsigned long flags;
2708  spin_lock_irqsave(&dispc.irq_lock, flags);
2709  dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST_DIGIT;
2710  dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
2711  _omap_dispc_set_irqs();
2712  spin_unlock_irqrestore(&dispc.irq_lock, flags);
2713  }
2714 }
2715 
2717 {
2718  return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2719 }
2720 
2721 void dispc_mgr_enable(enum omap_channel channel, bool enable)
2722 {
2723  if (dss_mgr_is_lcd(channel))
2724  dispc_mgr_enable_lcd_out(channel, enable);
2725  else if (channel == OMAP_DSS_CHANNEL_DIGIT)
2726  dispc_mgr_enable_digit_out(enable);
2727  else
2728  BUG();
2729 }
2730 
2731 void dispc_wb_enable(bool enable)
2732 {
2733  enum omap_plane plane = OMAP_DSS_WB;
2734  struct completion frame_done_completion;
2735  bool is_on;
2736  int r;
2737  u32 irq;
2738 
2739  is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
2740  irq = DISPC_IRQ_FRAMEDONEWB;
2741 
2742  if (!enable && is_on) {
2743  init_completion(&frame_done_completion);
2744 
2745  r = omap_dispc_register_isr(dispc_disable_isr,
2746  &frame_done_completion, irq);
2747  if (r)
2748  DSSERR("failed to register FRAMEDONEWB isr\n");
2749  }
2750 
2751  REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
2752 
2753  if (!enable && is_on) {
2754  if (!wait_for_completion_timeout(&frame_done_completion,
2755  msecs_to_jiffies(100)))
2756  DSSERR("timeout waiting for FRAMEDONEWB\n");
2757 
2758  r = omap_dispc_unregister_isr(dispc_disable_isr,
2759  &frame_done_completion, irq);
2760  if (r)
2761  DSSERR("failed to unregister FRAMEDONEWB isr\n");
2762  }
2763 }
2764 
2766 {
2767  enum omap_plane plane = OMAP_DSS_WB;
2768 
2769  return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
2770 }
2771 
2773 {
2775  return;
2776 
2777  REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
2778 }
2779 
2780 void dispc_lcd_enable_signal(bool enable)
2781 {
2783  return;
2784 
2785  REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
2786 }
2787 
2788 void dispc_pck_free_enable(bool enable)
2789 {
2791  return;
2792 
2793  REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
2794 }
2795 
2796 void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
2797 {
2798  mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
2799 }
2800 
2801 
2803 {
2804  mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
2805 }
2806 
2808 {
2809  REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
2810 }
2811 
2812 
2813 static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
2814 {
2815  dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
2816 }
2817 
2818 static void dispc_mgr_set_trans_key(enum omap_channel ch,
2820  u32 trans_key)
2821 {
2822  mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);
2823 
2824  dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
2825 }
2826 
2827 static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
2828 {
2829  mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);
2830 }
2831 
2832 static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
2833  bool enable)
2834 {
2836  return;
2837 
2838  if (ch == OMAP_DSS_CHANNEL_LCD)
2839  REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
2840  else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2841  REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
2842 }
2843 
2844 void dispc_mgr_setup(enum omap_channel channel,
2846 {
2847  dispc_mgr_set_default_color(channel, info->default_color);
2848  dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
2849  dispc_mgr_enable_trans_key(channel, info->trans_enabled);
2850  dispc_mgr_enable_alpha_fixed_zorder(channel,
2851  info->partial_alpha_enabled);
2852  if (dss_has_feature(FEAT_CPR)) {
2853  dispc_mgr_enable_cpr(channel, info->cpr_enable);
2854  dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
2855  }
2856 }
2857 
2859 {
2860  int code;
2861 
2862  switch (data_lines) {
2863  case 12:
2864  code = 0;
2865  break;
2866  case 16:
2867  code = 1;
2868  break;
2869  case 18:
2870  code = 2;
2871  break;
2872  case 24:
2873  code = 3;
2874  break;
2875  default:
2876  BUG();
2877  return;
2878  }
2879 
2880  mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);
2881 }
2882 
2884 {
2885  u32 l;
2886  int gpout0, gpout1;
2887 
2888  switch (mode) {
2889  case DSS_IO_PAD_MODE_RESET:
2890  gpout0 = 0;
2891  gpout1 = 0;
2892  break;
2893  case DSS_IO_PAD_MODE_RFBI:
2894  gpout0 = 1;
2895  gpout1 = 0;
2896  break;
2898  gpout0 = 1;
2899  gpout1 = 1;
2900  break;
2901  default:
2902  BUG();
2903  return;
2904  }
2905 
2906  l = dispc_read_reg(DISPC_CONTROL);
2907  l = FLD_MOD(l, gpout0, 15, 15);
2908  l = FLD_MOD(l, gpout1, 16, 16);
2909  dispc_write_reg(DISPC_CONTROL, l);
2910 }
2911 
2912 void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
2913 {
2914  mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);
2915 }
2916 
2917 static bool _dispc_mgr_size_ok(u16 width, u16 height)
2918 {
2919  return width <= dss_feat_get_param_max(FEAT_PARAM_MGR_WIDTH) &&
2921 }
2922 
2923 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2924  int vsw, int vfp, int vbp)
2925 {
2926  if (hsw < 1 || hsw > dispc.feat->sw_max ||
2927  hfp < 1 || hfp > dispc.feat->hp_max ||
2928  hbp < 1 || hbp > dispc.feat->hp_max ||
2929  vsw < 1 || vsw > dispc.feat->sw_max ||
2930  vfp < 0 || vfp > dispc.feat->vp_max ||
2931  vbp < 0 || vbp > dispc.feat->vp_max)
2932  return false;
2933  return true;
2934 }
2935 
2937  const struct omap_video_timings *timings)
2938 {
2939  bool timings_ok;
2940 
2941  timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
2942 
2943  if (dss_mgr_is_lcd(channel))
2944  timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw,
2945  timings->hfp, timings->hbp,
2946  timings->vsw, timings->vfp,
2947  timings->vbp);
2948 
2949  return timings_ok;
2950 }
2951 
2952 static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
2953  int hfp, int hbp, int vsw, int vfp, int vbp,
2954  enum omap_dss_signal_level vsync_level,
2955  enum omap_dss_signal_level hsync_level,
2956  enum omap_dss_signal_edge data_pclk_edge,
2957  enum omap_dss_signal_level de_level,
2958  enum omap_dss_signal_edge sync_pclk_edge)
2959 
2960 {
2961  u32 timing_h, timing_v, l;
2962  bool onoff, rf, ipc;
2963 
2964  timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
2965  FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
2966  FLD_VAL(hbp-1, dispc.feat->bp_start, 20);
2967  timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) |
2968  FLD_VAL(vfp, dispc.feat->fp_start, 8) |
2969  FLD_VAL(vbp, dispc.feat->bp_start, 20);
2970 
2971  dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
2972  dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
2973 
2974  switch (data_pclk_edge) {
2976  ipc = false;
2977  break;
2979  ipc = true;
2980  break;
2982  default:
2983  BUG();
2984  }
2985 
2986  switch (sync_pclk_edge) {
2988  onoff = false;
2989  rf = false;
2990  break;
2992  onoff = true;
2993  rf = false;
2994  break;
2996  onoff = true;
2997  rf = true;
2998  break;
2999  default:
3000  BUG();
3001  };
3002 
3003  l = dispc_read_reg(DISPC_POL_FREQ(channel));
3004  l |= FLD_VAL(onoff, 17, 17);
3005  l |= FLD_VAL(rf, 16, 16);
3006  l |= FLD_VAL(de_level, 15, 15);
3007  l |= FLD_VAL(ipc, 14, 14);
3008  l |= FLD_VAL(hsync_level, 13, 13);
3009  l |= FLD_VAL(vsync_level, 12, 12);
3010  dispc_write_reg(DISPC_POL_FREQ(channel), l);
3011 }
3012 
3013 /* change name to mode? */
3015  struct omap_video_timings *timings)
3016 {
3017  unsigned xtot, ytot;
3018  unsigned long ht, vt;
3019  struct omap_video_timings t = *timings;
3020 
3021  DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res);
3022 
3023  if (!dispc_mgr_timings_ok(channel, &t)) {
3024  BUG();
3025  return;
3026  }
3027 
3028  if (dss_mgr_is_lcd(channel)) {
3029  _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw,
3030  t.vfp, t.vbp, t.vsync_level, t.hsync_level,
3032 
3033  xtot = t.x_res + t.hfp + t.hsw + t.hbp;
3034  ytot = t.y_res + t.vfp + t.vsw + t.vbp;
3035 
3036  ht = (timings->pixel_clock * 1000) / xtot;
3037  vt = (timings->pixel_clock * 1000) / xtot / ytot;
3038 
3039  DSSDBG("pck %u\n", timings->pixel_clock);
3040  DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
3041  t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp);
3042  DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
3044  t.de_level, t.sync_pclk_edge);
3045 
3046  DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
3047  } else {
3048  if (t.interlace == true)
3049  t.y_res /= 2;
3050  }
3051 
3052  dispc_mgr_set_size(channel, t.x_res, t.y_res);
3053 }
3054 
3055 static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
3056  u16 pck_div)
3057 {
3058  BUG_ON(lck_div < 1);
3059  BUG_ON(pck_div < 1);
3060 
3061  dispc_write_reg(DISPC_DIVISORo(channel),
3062  FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
3063 }
3064 
3065 static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
3066  int *pck_div)
3067 {
3068  u32 l;
3069  l = dispc_read_reg(DISPC_DIVISORo(channel));
3070  *lck_div = FLD_GET(l, 23, 16);
3071  *pck_div = FLD_GET(l, 7, 0);
3072 }
3073 
3074 unsigned long dispc_fclk_rate(void)
3075 {
3076  struct platform_device *dsidev;
3077  unsigned long r = 0;
3078 
3079  switch (dss_get_dispc_clk_source()) {
3080  case OMAP_DSS_CLK_SRC_FCK:
3081  r = clk_get_rate(dispc.dss_clk);
3082  break;
3084  dsidev = dsi_get_dsidev_from_id(0);
3085  r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
3086  break;
3088  dsidev = dsi_get_dsidev_from_id(1);
3089  r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
3090  break;
3091  default:
3092  BUG();
3093  return 0;
3094  }
3095 
3096  return r;
3097 }
3098 
3099 unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
3100 {
3101  struct platform_device *dsidev;
3102  int lcd;
3103  unsigned long r;
3104  u32 l;
3105 
3106  l = dispc_read_reg(DISPC_DIVISORo(channel));
3107 
3108  lcd = FLD_GET(l, 23, 16);
3109 
3110  switch (dss_get_lcd_clk_source(channel)) {
3111  case OMAP_DSS_CLK_SRC_FCK:
3112  r = clk_get_rate(dispc.dss_clk);
3113  break;
3115  dsidev = dsi_get_dsidev_from_id(0);
3116  r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
3117  break;
3119  dsidev = dsi_get_dsidev_from_id(1);
3120  r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
3121  break;
3122  default:
3123  BUG();
3124  return 0;
3125  }
3126 
3127  return r / lcd;
3128 }
3129 
3130 unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
3131 {
3132  unsigned long r;
3133 
3134  if (dss_mgr_is_lcd(channel)) {
3135  int pcd;
3136  u32 l;
3137 
3138  l = dispc_read_reg(DISPC_DIVISORo(channel));
3139 
3140  pcd = FLD_GET(l, 7, 0);
3141 
3142  r = dispc_mgr_lclk_rate(channel);
3143 
3144  return r / pcd;
3145  } else {
3147 
3148  source = dss_get_hdmi_venc_clk_source();
3149 
3150  switch (source) {
3151  case DSS_VENC_TV_CLK:
3152  return venc_get_pixel_clock();
3153  case DSS_HDMI_M_PCLK:
3154  return hdmi_get_pixel_clock();
3155  default:
3156  BUG();
3157  return 0;
3158  }
3159  }
3160 }
3161 
3162 unsigned long dispc_core_clk_rate(void)
3163 {
3164  int lcd;
3165  unsigned long fclk = dispc_fclk_rate();
3166 
3168  lcd = REG_GET(DISPC_DIVISOR, 23, 16);
3169  else
3170  lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16);
3171 
3172  return fclk / lcd;
3173 }
3174 
3175 static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
3176 {
3177  enum omap_channel channel = dispc_ovl_get_channel_out(plane);
3178 
3179  return dispc_mgr_pclk_rate(channel);
3180 }
3181 
3182 static unsigned long dispc_plane_lclk_rate(enum omap_plane plane)
3183 {
3184  enum omap_channel channel = dispc_ovl_get_channel_out(plane);
3185 
3186  if (dss_mgr_is_lcd(channel))
3187  return dispc_mgr_lclk_rate(channel);
3188  else
3189  return dispc_fclk_rate();
3190 
3191 }
3192 static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
3193 {
3194  int lcd, pcd;
3195  enum omap_dss_clk_source lcd_clk_src;
3196 
3197  seq_printf(s, "- %s -\n", mgr_desc[channel].name);
3198 
3199  lcd_clk_src = dss_get_lcd_clk_source(channel);
3200 
3201  seq_printf(s, "%s clk source = %s (%s)\n", mgr_desc[channel].name,
3202  dss_get_generic_clk_source_name(lcd_clk_src),
3203  dss_feat_get_clk_source_name(lcd_clk_src));
3204 
3205  dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd);
3206 
3207  seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3208  dispc_mgr_lclk_rate(channel), lcd);
3209  seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
3210  dispc_mgr_pclk_rate(channel), pcd);
3211 }
3212 
3214 {
3215  int lcd;
3216  u32 l;
3217  enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
3218 
3219  if (dispc_runtime_get())
3220  return;
3221 
3222  seq_printf(s, "- DISPC -\n");
3223 
3224  seq_printf(s, "dispc fclk source = %s (%s)\n",
3225  dss_get_generic_clk_source_name(dispc_clk_src),
3226  dss_feat_get_clk_source_name(dispc_clk_src));
3227 
3228  seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
3229 
3231  seq_printf(s, "- DISPC-CORE-CLK -\n");
3232  l = dispc_read_reg(DISPC_DIVISOR);
3233  lcd = FLD_GET(l, 23, 16);
3234 
3235  seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3236  (dispc_fclk_rate()/lcd), lcd);
3237  }
3238 
3239  dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD);
3240 
3242  dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2);
3244  dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);
3245 
3247 }
3248 
3249 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3250 void dispc_dump_irqs(struct seq_file *s)
3251 {
3252  unsigned long flags;
3253  struct dispc_irq_stats stats;
3254 
3255  spin_lock_irqsave(&dispc.irq_stats_lock, flags);
3256 
3257  stats = dispc.irq_stats;
3258  memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
3259  dispc.irq_stats.last_reset = jiffies;
3260 
3261  spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
3262 
3263  seq_printf(s, "period %u ms\n",
3264  jiffies_to_msecs(jiffies - stats.last_reset));
3265 
3266  seq_printf(s, "irqs %d\n", stats.irq_count);
3267 #define PIS(x) \
3268  seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
3269 
3270  PIS(FRAMEDONE);
3271  PIS(VSYNC);
3272  PIS(EVSYNC_EVEN);
3273  PIS(EVSYNC_ODD);
3274  PIS(ACBIAS_COUNT_STAT);
3275  PIS(PROG_LINE_NUM);
3276  PIS(GFX_FIFO_UNDERFLOW);
3277  PIS(GFX_END_WIN);
3278  PIS(PAL_GAMMA_MASK);
3279  PIS(OCP_ERR);
3280  PIS(VID1_FIFO_UNDERFLOW);
3281  PIS(VID1_END_WIN);
3282  PIS(VID2_FIFO_UNDERFLOW);
3283  PIS(VID2_END_WIN);
3284  if (dss_feat_get_num_ovls() > 3) {
3285  PIS(VID3_FIFO_UNDERFLOW);
3286  PIS(VID3_END_WIN);
3287  }
3288  PIS(SYNC_LOST);
3289  PIS(SYNC_LOST_DIGIT);
3290  PIS(WAKEUP);
3292  PIS(FRAMEDONE2);
3293  PIS(VSYNC2);
3294  PIS(ACBIAS_COUNT_STAT2);
3295  PIS(SYNC_LOST2);
3296  }
3298  PIS(FRAMEDONE3);
3299  PIS(VSYNC3);
3300  PIS(ACBIAS_COUNT_STAT3);
3301  PIS(SYNC_LOST3);
3302  }
3303 #undef PIS
3304 }
3305 #endif
3306 
3307 static void dispc_dump_regs(struct seq_file *s)
3308 {
3309  int i, j;
3310  const char *mgr_names[] = {
3311  [OMAP_DSS_CHANNEL_LCD] = "LCD",
3312  [OMAP_DSS_CHANNEL_DIGIT] = "TV",
3313  [OMAP_DSS_CHANNEL_LCD2] = "LCD2",
3314  [OMAP_DSS_CHANNEL_LCD3] = "LCD3",
3315  };
3316  const char *ovl_names[] = {
3317  [OMAP_DSS_GFX] = "GFX",
3318  [OMAP_DSS_VIDEO1] = "VID1",
3319  [OMAP_DSS_VIDEO2] = "VID2",
3320  [OMAP_DSS_VIDEO3] = "VID3",
3321  };
3322  const char **p_names;
3323 
3324 #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
3325 
3326  if (dispc_runtime_get())
3327  return;
3328 
3329  /* DISPC common registers */
3346  }
3350  }
3351 
3352 #undef DUMPREG
3353 
3354 #define DISPC_REG(i, name) name(i)
3355 #define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
3356  48 - strlen(#r) - strlen(p_names[i]), " ", \
3357  dispc_read_reg(DISPC_REG(i, r)))
3358 
3359  p_names = mgr_names;
3360 
3361  /* DISPC channel specific registers */
3362  for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
3363  DUMPREG(i, DISPC_DEFAULT_COLOR);
3364  DUMPREG(i, DISPC_TRANS_COLOR);
3365  DUMPREG(i, DISPC_SIZE_MGR);
3366 
3367  if (i == OMAP_DSS_CHANNEL_DIGIT)
3368  continue;
3369 
3370  DUMPREG(i, DISPC_DEFAULT_COLOR);
3371  DUMPREG(i, DISPC_TRANS_COLOR);
3372  DUMPREG(i, DISPC_TIMING_H);
3373  DUMPREG(i, DISPC_TIMING_V);
3374  DUMPREG(i, DISPC_POL_FREQ);
3375  DUMPREG(i, DISPC_DIVISORo);
3376  DUMPREG(i, DISPC_SIZE_MGR);
3377 
3378  DUMPREG(i, DISPC_DATA_CYCLE1);
3379  DUMPREG(i, DISPC_DATA_CYCLE2);
3380  DUMPREG(i, DISPC_DATA_CYCLE3);
3381 
3382  if (dss_has_feature(FEAT_CPR)) {
3383  DUMPREG(i, DISPC_CPR_COEF_R);
3384  DUMPREG(i, DISPC_CPR_COEF_G);
3385  DUMPREG(i, DISPC_CPR_COEF_B);
3386  }
3387  }
3388 
3389  p_names = ovl_names;
3390 
3391  for (i = 0; i < dss_feat_get_num_ovls(); i++) {
3392  DUMPREG(i, DISPC_OVL_BA0);
3393  DUMPREG(i, DISPC_OVL_BA1);
3395  DUMPREG(i, DISPC_OVL_SIZE);
3403 
3404  if (i == OMAP_DSS_GFX) {
3407  continue;
3408  }
3409 
3410  DUMPREG(i, DISPC_OVL_FIR);
3417  DUMPREG(i, DISPC_OVL_FIR2);
3420  }
3425  }
3426 
3427 #undef DISPC_REG
3428 #undef DUMPREG
3429 
3430 #define DISPC_REG(plane, name, i) name(plane, i)
3431 #define DUMPREG(plane, name, i) \
3432  seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
3433  46 - strlen(#name) - strlen(p_names[plane]), " ", \
3434  dispc_read_reg(DISPC_REG(plane, name, i)))
3435 
3436  /* Video pipeline coefficient registers */
3437 
3438  /* start from OMAP_DSS_VIDEO1 */
3439  for (i = 1; i < dss_feat_get_num_ovls(); i++) {
3440  for (j = 0; j < 8; j++)
3442 
3443  for (j = 0; j < 8; j++)
3445 
3446  for (j = 0; j < 5; j++)
3448 
3450  for (j = 0; j < 8; j++)
3452  }
3453 
3455  for (j = 0; j < 8; j++)
3457 
3458  for (j = 0; j < 8; j++)
3460 
3461  for (j = 0; j < 8; j++)
3463  }
3464  }
3465 
3467 
3468 #undef DISPC_REG
3469 #undef DUMPREG
3470 }
3471 
3472 /* with fck as input clock rate, find dispc dividers that produce req_pck */
3473 void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,
3474  struct dispc_clock_info *cinfo)
3475 {
3476  u16 pcd_min, pcd_max;
3477  unsigned long best_pck;
3478  u16 best_ld, cur_ld;
3479  u16 best_pd, cur_pd;
3480 
3483 
3484  best_pck = 0;
3485  best_ld = 0;
3486  best_pd = 0;
3487 
3488  for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
3489  unsigned long lck = fck / cur_ld;
3490 
3491  for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) {
3492  unsigned long pck = lck / cur_pd;
3493  long old_delta = abs(best_pck - req_pck);
3494  long new_delta = abs(pck - req_pck);
3495 
3496  if (best_pck == 0 || new_delta < old_delta) {
3497  best_pck = pck;
3498  best_ld = cur_ld;
3499  best_pd = cur_pd;
3500 
3501  if (pck == req_pck)
3502  goto found;
3503  }
3504 
3505  if (pck < req_pck)
3506  break;
3507  }
3508 
3509  if (lck / pcd_min < req_pck)
3510  break;
3511  }
3512 
3513 found:
3514  cinfo->lck_div = best_ld;
3515  cinfo->pck_div = best_pd;
3516  cinfo->lck = fck / cinfo->lck_div;
3517  cinfo->pck = cinfo->lck / cinfo->pck_div;
3518 }
3519 
3520 /* calculate clock rates using dividers in cinfo */
3522  struct dispc_clock_info *cinfo)
3523 {
3524  if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
3525  return -EINVAL;
3526  if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
3527  return -EINVAL;
3528 
3529  cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
3530  cinfo->pck = cinfo->lck / cinfo->pck_div;
3531 
3532  return 0;
3533 }
3534 
3536  struct dispc_clock_info *cinfo)
3537 {
3538  DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
3539  DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
3540 
3541  dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
3542 }
3543 
3545  struct dispc_clock_info *cinfo)
3546 {
3547  unsigned long fck;
3548 
3549  fck = dispc_fclk_rate();
3550 
3551  cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3552  cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
3553 
3554  cinfo->lck = fck / cinfo->lck_div;
3555  cinfo->pck = cinfo->lck / cinfo->pck_div;
3556 
3557  return 0;
3558 }
3559 
3560 /* dispc.irq_lock has to be locked by the caller */
3561 static void _omap_dispc_set_irqs(void)
3562 {
3563  u32 mask;
3564  u32 old_mask;
3565  int i;
3566  struct omap_dispc_isr_data *isr_data;
3567 
3568  mask = dispc.irq_error_mask;
3569 
3570  for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3571  isr_data = &dispc.registered_isr[i];
3572 
3573  if (isr_data->isr == NULL)
3574  continue;
3575 
3576  mask |= isr_data->mask;
3577  }
3578 
3579  old_mask = dispc_read_reg(DISPC_IRQENABLE);
3580  /* clear the irqstatus for newly enabled irqs */
3581  dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
3582 
3583  dispc_write_reg(DISPC_IRQENABLE, mask);
3584 }
3585 
3587 {
3588  int i;
3589  int ret;
3590  unsigned long flags;
3591  struct omap_dispc_isr_data *isr_data;
3592 
3593  if (isr == NULL)
3594  return -EINVAL;
3595 
3596  spin_lock_irqsave(&dispc.irq_lock, flags);
3597 
3598  /* check for duplicate entry */
3599  for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3600  isr_data = &dispc.registered_isr[i];
3601  if (isr_data->isr == isr && isr_data->arg == arg &&
3602  isr_data->mask == mask) {
3603  ret = -EINVAL;
3604  goto err;
3605  }
3606  }
3607 
3608  isr_data = NULL;
3609  ret = -EBUSY;
3610 
3611  for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3612  isr_data = &dispc.registered_isr[i];
3613 
3614  if (isr_data->isr != NULL)
3615  continue;
3616 
3617  isr_data->isr = isr;
3618  isr_data->arg = arg;
3619  isr_data->mask = mask;
3620  ret = 0;
3621 
3622  break;
3623  }
3624 
3625  if (ret)
3626  goto err;
3627 
3628  _omap_dispc_set_irqs();
3629 
3630  spin_unlock_irqrestore(&dispc.irq_lock, flags);
3631 
3632  return 0;
3633 err:
3634  spin_unlock_irqrestore(&dispc.irq_lock, flags);
3635 
3636  return ret;
3637 }
3639 
3641 {
3642  int i;
3643  unsigned long flags;
3644  int ret = -EINVAL;
3645  struct omap_dispc_isr_data *isr_data;
3646 
3647  spin_lock_irqsave(&dispc.irq_lock, flags);
3648 
3649  for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3650  isr_data = &dispc.registered_isr[i];
3651  if (isr_data->isr != isr || isr_data->arg != arg ||
3652  isr_data->mask != mask)
3653  continue;
3654 
3655  /* found the correct isr */
3656 
3657  isr_data->isr = NULL;
3658  isr_data->arg = NULL;
3659  isr_data->mask = 0;
3660 
3661  ret = 0;
3662  break;
3663  }
3664 
3665  if (ret == 0)
3666  _omap_dispc_set_irqs();
3667 
3668  spin_unlock_irqrestore(&dispc.irq_lock, flags);
3669 
3670  return ret;
3671 }
3673 
3674 #ifdef DEBUG
3675 static void print_irq_status(u32 status)
3676 {
3677  if ((status & dispc.irq_error_mask) == 0)
3678  return;
3679 
3680  printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
3681 
3682 #define PIS(x) \
3683  if (status & DISPC_IRQ_##x) \
3684  printk(#x " ");
3685  PIS(GFX_FIFO_UNDERFLOW);
3686  PIS(OCP_ERR);
3687  PIS(VID1_FIFO_UNDERFLOW);
3688  PIS(VID2_FIFO_UNDERFLOW);
3689  if (dss_feat_get_num_ovls() > 3)
3690  PIS(VID3_FIFO_UNDERFLOW);
3691  PIS(SYNC_LOST);
3692  PIS(SYNC_LOST_DIGIT);
3694  PIS(SYNC_LOST2);
3696  PIS(SYNC_LOST3);
3697 #undef PIS
3698 
3699  printk("\n");
3700 }
3701 #endif
3702 
3703 /* Called from dss.c. Note that we don't touch clocks here,
3704  * but we presume they are on because we got an IRQ. However,
3705  * an irq handler may turn the clocks off, so we may not have
3706  * clock later in the function. */
3707 static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
3708 {
3709  int i;
3710  u32 irqstatus, irqenable;
3711  u32 handledirqs = 0;
3712  u32 unhandled_errors;
3713  struct omap_dispc_isr_data *isr_data;
3714  struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
3715 
3716  spin_lock(&dispc.irq_lock);
3717 
3718  irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
3719  irqenable = dispc_read_reg(DISPC_IRQENABLE);
3720 
3721  /* IRQ is not for us */
3722  if (!(irqstatus & irqenable)) {
3723  spin_unlock(&dispc.irq_lock);
3724  return IRQ_NONE;
3725  }
3726 
3727 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3728  spin_lock(&dispc.irq_stats_lock);
3729  dispc.irq_stats.irq_count++;
3730  dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
3731  spin_unlock(&dispc.irq_stats_lock);
3732 #endif
3733 
3734 #ifdef DEBUG
3735  if (dss_debug)
3736  print_irq_status(irqstatus);
3737 #endif
3738  /* Ack the interrupt. Do it here before clocks are possibly turned
3739  * off */
3740  dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
3741  /* flush posted write */
3742  dispc_read_reg(DISPC_IRQSTATUS);
3743 
3744  /* make a copy and unlock, so that isrs can unregister
3745  * themselves */
3746  memcpy(registered_isr, dispc.registered_isr,
3747  sizeof(registered_isr));
3748 
3749  spin_unlock(&dispc.irq_lock);
3750 
3751  for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3752  isr_data = &registered_isr[i];
3753 
3754  if (!isr_data->isr)
3755  continue;
3756 
3757  if (isr_data->mask & irqstatus) {
3758  isr_data->isr(isr_data->arg, irqstatus);
3759  handledirqs |= isr_data->mask;
3760  }
3761  }
3762 
3763  spin_lock(&dispc.irq_lock);
3764 
3765  unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
3766 
3767  if (unhandled_errors) {
3768  dispc.error_irqs |= unhandled_errors;
3769 
3770  dispc.irq_error_mask &= ~unhandled_errors;
3771  _omap_dispc_set_irqs();
3772 
3773  schedule_work(&dispc.error_work);
3774  }
3775 
3776  spin_unlock(&dispc.irq_lock);
3777 
3778  return IRQ_HANDLED;
3779 }
3780 
3781 static void dispc_error_worker(struct work_struct *work)
3782 {
3783  int i;
3784  u32 errors;
3785  unsigned long flags;
3786  static const unsigned fifo_underflow_bits[] = {
3791  };
3792 
3793  spin_lock_irqsave(&dispc.irq_lock, flags);
3794  errors = dispc.error_irqs;
3795  dispc.error_irqs = 0;
3796  spin_unlock_irqrestore(&dispc.irq_lock, flags);
3797 
3799 
3800  for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3801  struct omap_overlay *ovl;
3802  unsigned bit;
3803 
3804  ovl = omap_dss_get_overlay(i);
3805  bit = fifo_underflow_bits[i];
3806 
3807  if (bit & errors) {
3808  DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
3809  ovl->name);
3810  dispc_ovl_enable(ovl->id, false);
3811  dispc_mgr_go(ovl->manager->id);
3812  msleep(50);
3813  }
3814  }
3815 
3816  for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3817  struct omap_overlay_manager *mgr;
3818  unsigned bit;
3819 
3821  bit = mgr_desc[i].sync_lost_irq;
3822 
3823  if (bit & errors) {
3824  struct omap_dss_device *dssdev = mgr->get_device(mgr);
3825  bool enable;
3826 
3827  DSSERR("SYNC_LOST on channel %s, restarting the output "
3828  "with video overlays disabled\n",
3829  mgr->name);
3830 
3831  enable = dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
3832  dssdev->driver->disable(dssdev);
3833 
3834  for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3835  struct omap_overlay *ovl;
3836  ovl = omap_dss_get_overlay(i);
3837 
3838  if (ovl->id != OMAP_DSS_GFX &&
3839  ovl->manager == mgr)
3840  dispc_ovl_enable(ovl->id, false);
3841  }
3842 
3843  dispc_mgr_go(mgr->id);
3844  msleep(50);
3845 
3846  if (enable)
3847  dssdev->driver->enable(dssdev);
3848  }
3849  }
3850 
3851  if (errors & DISPC_IRQ_OCP_ERR) {
3852  DSSERR("OCP_ERR\n");
3853  for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3854  struct omap_overlay_manager *mgr;
3855  struct omap_dss_device *dssdev;
3856 
3858  dssdev = mgr->get_device(mgr);
3859 
3860  if (dssdev && dssdev->driver)
3861  dssdev->driver->disable(dssdev);
3862  }
3863  }
3864 
3865  spin_lock_irqsave(&dispc.irq_lock, flags);
3866  dispc.irq_error_mask |= errors;
3867  _omap_dispc_set_irqs();
3868  spin_unlock_irqrestore(&dispc.irq_lock, flags);
3869 
3871 }
3872 
3873 int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
3874 {
3875  void dispc_irq_wait_handler(void *data, u32 mask)
3876  {
3877  complete((struct completion *)data);
3878  }
3879 
3880  int r;
3882 
3883  r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
3884  irqmask);
3885 
3886  if (r)
3887  return r;
3888 
3889  timeout = wait_for_completion_timeout(&completion, timeout);
3890 
3891  omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3892 
3893  if (timeout == 0)
3894  return -ETIMEDOUT;
3895 
3896  if (timeout == -ERESTARTSYS)
3897  return -ERESTARTSYS;
3898 
3899  return 0;
3900 }
3901 
3903  unsigned long timeout)
3904 {
3905  void dispc_irq_wait_handler(void *data, u32 mask)
3906  {
3907  complete((struct completion *)data);
3908  }
3909 
3910  int r;
3912 
3913  r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
3914  irqmask);
3915 
3916  if (r)
3917  return r;
3918 
3920  timeout);
3921 
3922  omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3923 
3924  if (timeout == 0)
3925  return -ETIMEDOUT;
3926 
3927  if (timeout == -ERESTARTSYS)
3928  return -ERESTARTSYS;
3929 
3930  return 0;
3931 }
3932 
3933 static void _omap_dispc_initialize_irq(void)
3934 {
3935  unsigned long flags;
3936 
3937  spin_lock_irqsave(&dispc.irq_lock, flags);
3938 
3939  memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3940 
3941  dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
3943  dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
3945  dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
3946  if (dss_feat_get_num_ovls() > 3)
3947  dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
3948 
3949  /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3950  * so clear it */
3951  dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
3952 
3953  _omap_dispc_set_irqs();
3954 
3955  spin_unlock_irqrestore(&dispc.irq_lock, flags);
3956 }
3957 
3959 {
3960  REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3961 }
3962 
3964 {
3965  REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3966 }
3967 
3968 static void _omap_dispc_initial_config(void)
3969 {
3970  u32 l;
3971 
3972  /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3974  l = dispc_read_reg(DISPC_DIVISOR);
3975  /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3976  l = FLD_MOD(l, 1, 0, 0);
3977  l = FLD_MOD(l, 1, 23, 16);
3978  dispc_write_reg(DISPC_DIVISOR, l);
3979  }
3980 
3981  /* FUNCGATED */
3983  REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3984 
3985  dispc_setup_color_conv_coef();
3986 
3988 
3989  dispc_init_fifos();
3990 
3991  dispc_configure_burst_sizes();
3992 
3993  dispc_ovl_enable_zorder_planes();
3994 }
3995 
3996 static const struct dispc_features omap24xx_dispc_feats __initconst = {
3997  .sw_start = 5,
3998  .fp_start = 15,
3999  .bp_start = 27,
4000  .sw_max = 64,
4001  .vp_max = 255,
4002  .hp_max = 256,
4003  .calc_scaling = dispc_ovl_calc_scaling_24xx,
4004  .calc_core_clk = calc_core_clk_24xx,
4005  .num_fifos = 3,
4006 };
4007 
4008 static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
4009  .sw_start = 5,
4010  .fp_start = 15,
4011  .bp_start = 27,
4012  .sw_max = 64,
4013  .vp_max = 255,
4014  .hp_max = 256,
4015  .calc_scaling = dispc_ovl_calc_scaling_34xx,
4016  .calc_core_clk = calc_core_clk_34xx,
4017  .num_fifos = 3,
4018 };
4019 
4020 static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
4021  .sw_start = 7,
4022  .fp_start = 19,
4023  .bp_start = 31,
4024  .sw_max = 256,
4025  .vp_max = 4095,
4026  .hp_max = 4096,
4027  .calc_scaling = dispc_ovl_calc_scaling_34xx,
4028  .calc_core_clk = calc_core_clk_34xx,
4029  .num_fifos = 3,
4030 };
4031 
4032 static const struct dispc_features omap44xx_dispc_feats __initconst = {
4033  .sw_start = 7,
4034  .fp_start = 19,
4035  .bp_start = 31,
4036  .sw_max = 256,
4037  .vp_max = 4095,
4038  .hp_max = 4096,
4039  .calc_scaling = dispc_ovl_calc_scaling_44xx,
4040  .calc_core_clk = calc_core_clk_44xx,
4041  .num_fifos = 5,
4042  .gfx_fifo_workaround = true,
4043 };
4044 
4045 static int __init dispc_init_features(struct device *dev)
4046 {
4047  const struct dispc_features *src;
4048  struct dispc_features *dst;
4049 
4050  dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
4051  if (!dst) {
4052  dev_err(dev, "Failed to allocate DISPC Features\n");
4053  return -ENOMEM;
4054  }
4055 
4056  if (cpu_is_omap24xx()) {
4057  src = &omap24xx_dispc_feats;
4058  } else if (cpu_is_omap34xx()) {
4059  if (omap_rev() < OMAP3430_REV_ES3_0)
4060  src = &omap34xx_rev1_0_dispc_feats;
4061  else
4062  src = &omap34xx_rev3_0_dispc_feats;
4063  } else if (cpu_is_omap44xx()) {
4064  src = &omap44xx_dispc_feats;
4065  } else if (soc_is_omap54xx()) {
4066  src = &omap44xx_dispc_feats;
4067  } else {
4068  return -ENODEV;
4069  }
4070 
4071  memcpy(dst, src, sizeof(*dst));
4072  dispc.feat = dst;
4073 
4074  return 0;
4075 }
4076 
4077 /* DISPC HW IP initialisation */
4078 static int __init omap_dispchw_probe(struct platform_device *pdev)
4079 {
4080  u32 rev;
4081  int r = 0;
4082  struct resource *dispc_mem;
4083  struct clk *clk;
4084 
4085  dispc.pdev = pdev;
4086 
4087  r = dispc_init_features(&dispc.pdev->dev);
4088  if (r)
4089  return r;
4090 
4091  spin_lock_init(&dispc.irq_lock);
4092 
4093 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
4094  spin_lock_init(&dispc.irq_stats_lock);
4095  dispc.irq_stats.last_reset = jiffies;
4096 #endif
4097 
4098  INIT_WORK(&dispc.error_work, dispc_error_worker);
4099 
4100  dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
4101  if (!dispc_mem) {
4102  DSSERR("can't get IORESOURCE_MEM DISPC\n");
4103  return -EINVAL;
4104  }
4105 
4106  dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start,
4107  resource_size(dispc_mem));
4108  if (!dispc.base) {
4109  DSSERR("can't ioremap DISPC\n");
4110  return -ENOMEM;
4111  }
4112 
4113  dispc.irq = platform_get_irq(dispc.pdev, 0);
4114  if (dispc.irq < 0) {
4115  DSSERR("platform_get_irq failed\n");
4116  return -ENODEV;
4117  }
4118 
4119  r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler,
4120  IRQF_SHARED, "OMAP DISPC", dispc.pdev);
4121  if (r < 0) {
4122  DSSERR("request_irq failed\n");
4123  return r;
4124  }
4125 
4126  clk = clk_get(&pdev->dev, "fck");
4127  if (IS_ERR(clk)) {
4128  DSSERR("can't get fck\n");
4129  r = PTR_ERR(clk);
4130  return r;
4131  }
4132 
4133  dispc.dss_clk = clk;
4134 
4135  pm_runtime_enable(&pdev->dev);
4136 
4137  r = dispc_runtime_get();
4138  if (r)
4139  goto err_runtime_get;
4140 
4141  _omap_dispc_initial_config();
4142 
4143  _omap_dispc_initialize_irq();
4144 
4145  rev = dispc_read_reg(DISPC_REVISION);
4146  dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
4147  FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
4148 
4150 
4151  dss_debugfs_create_file("dispc", dispc_dump_regs);
4152 
4153 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
4154  dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
4155 #endif
4156  return 0;
4157 
4158 err_runtime_get:
4159  pm_runtime_disable(&pdev->dev);
4160  clk_put(dispc.dss_clk);
4161  return r;
4162 }
4163 
4164 static int __exit omap_dispchw_remove(struct platform_device *pdev)
4165 {
4166  pm_runtime_disable(&pdev->dev);
4167 
4168  clk_put(dispc.dss_clk);
4169 
4170  return 0;
4171 }
4172 
4173 static int dispc_runtime_suspend(struct device *dev)
4174 {
4175  dispc_save_context();
4176 
4177  return 0;
4178 }
4179 
4180 static int dispc_runtime_resume(struct device *dev)
4181 {
4182  dispc_restore_context();
4183 
4184  return 0;
4185 }
4186 
4187 static const struct dev_pm_ops dispc_pm_ops = {
4188  .runtime_suspend = dispc_runtime_suspend,
4189  .runtime_resume = dispc_runtime_resume,
4190 };
4191 
4192 static struct platform_driver omap_dispchw_driver = {
4193  .remove = __exit_p(omap_dispchw_remove),
4194  .driver = {
4195  .name = "omapdss_dispc",
4196  .owner = THIS_MODULE,
4197  .pm = &dispc_pm_ops,
4198  },
4199 };
4200 
4202 {
4203  return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe);
4204 }
4205 
4207 {
4208  platform_driver_unregister(&omap_dispchw_driver);
4209 }