root/drivers/video/fbdev/omap2/omapfb/dss/dispc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dispc_write_reg
  2. dispc_read_reg
  3. mgr_fld_read
  4. mgr_fld_write
  5. dispc_save_context
  6. dispc_restore_context
  7. dispc_runtime_get
  8. dispc_runtime_put
  9. dispc_mgr_get_vsync_irq
  10. dispc_mgr_get_framedone_irq
  11. dispc_mgr_get_sync_lost_irq
  12. dispc_wb_get_framedone_irq
  13. dispc_mgr_go_busy
  14. dispc_mgr_go
  15. dispc_wb_go_busy
  16. dispc_wb_go
  17. dispc_ovl_write_firh_reg
  18. dispc_ovl_write_firhv_reg
  19. dispc_ovl_write_firv_reg
  20. dispc_ovl_write_firh2_reg
  21. dispc_ovl_write_firhv2_reg
  22. dispc_ovl_write_firv2_reg
  23. dispc_ovl_set_scale_coef
  24. dispc_ovl_write_color_conv_coef
  25. dispc_setup_color_conv_coef
  26. dispc_ovl_set_ba0
  27. dispc_ovl_set_ba1
  28. dispc_ovl_set_ba0_uv
  29. dispc_ovl_set_ba1_uv
  30. dispc_ovl_set_pos
  31. dispc_ovl_set_input_size
  32. dispc_ovl_set_output_size
  33. dispc_ovl_set_zorder
  34. dispc_ovl_enable_zorder_planes
  35. dispc_ovl_set_pre_mult_alpha
  36. dispc_ovl_setup_global_alpha
  37. dispc_ovl_set_pix_inc
  38. dispc_ovl_set_row_inc
  39. dispc_ovl_set_color_mode
  40. dispc_ovl_configure_burst_type
  41. dispc_ovl_set_channel_out
  42. dispc_ovl_get_channel_out
  43. dispc_wb_set_channel_in
  44. dispc_ovl_set_burst_size
  45. dispc_configure_burst_sizes
  46. dispc_ovl_get_burst_size
  47. dispc_enable_gamma_table
  48. dispc_mgr_enable_cpr
  49. dispc_mgr_set_cpr_coef
  50. dispc_ovl_set_vid_color_conv
  51. dispc_ovl_enable_replication
  52. dispc_mgr_set_size
  53. dispc_init_fifos
  54. dispc_ovl_get_fifo_size
  55. dispc_ovl_set_fifo_threshold
  56. dispc_enable_fifomerge
  57. dispc_ovl_compute_fifo_thresholds
  58. dispc_ovl_set_mflag
  59. dispc_ovl_set_mflag_threshold
  60. dispc_init_mflag
  61. dispc_ovl_set_fir
  62. dispc_ovl_set_vid_accu0
  63. dispc_ovl_set_vid_accu1
  64. dispc_ovl_set_vid_accu2_0
  65. dispc_ovl_set_vid_accu2_1
  66. dispc_ovl_set_scale_param
  67. dispc_ovl_set_accu_uv
  68. dispc_ovl_set_scaling_common
  69. dispc_ovl_set_scaling_uv
  70. dispc_ovl_set_scaling
  71. dispc_ovl_set_rotation_attrs
  72. color_mode_to_bpp
  73. pixinc
  74. calc_vrfb_rotation_offset
  75. calc_dma_rotation_offset
  76. calc_tiler_rotation_offset
  77. check_horiz_timing_omap3
  78. calc_core_clk_five_taps
  79. calc_core_clk_24xx
  80. calc_core_clk_34xx
  81. calc_core_clk_44xx
  82. dispc_ovl_calc_scaling_24xx
  83. dispc_ovl_calc_scaling_34xx
  84. dispc_ovl_calc_scaling_44xx
  85. dispc_ovl_calc_scaling
  86. dispc_ovl_check
  87. dispc_ovl_setup_common
  88. dispc_ovl_setup
  89. dispc_wb_setup
  90. dispc_ovl_enable
  91. dispc_ovl_enabled
  92. dispc_mgr_enable
  93. dispc_mgr_is_enabled
  94. dispc_wb_enable
  95. dispc_wb_is_enabled
  96. dispc_lcd_enable_signal_polarity
  97. dispc_lcd_enable_signal
  98. dispc_pck_free_enable
  99. dispc_mgr_enable_fifohandcheck
  100. dispc_mgr_set_lcd_type_tft
  101. dispc_set_loadmode
  102. dispc_mgr_set_default_color
  103. dispc_mgr_set_trans_key
  104. dispc_mgr_enable_trans_key
  105. dispc_mgr_enable_alpha_fixed_zorder
  106. dispc_mgr_setup
  107. dispc_mgr_set_tft_data_lines
  108. dispc_mgr_set_io_pad_mode
  109. dispc_mgr_enable_stallmode
  110. dispc_mgr_set_lcd_config
  111. _dispc_mgr_size_ok
  112. _dispc_lcd_timings_ok
  113. _dispc_mgr_pclk_ok
  114. dispc_mgr_timings_ok
  115. _dispc_mgr_set_lcd_timings
  116. dispc_mgr_set_timings
  117. dispc_mgr_set_lcd_divisor
  118. dispc_mgr_get_lcd_divisor
  119. dispc_fclk_rate
  120. dispc_mgr_lclk_rate
  121. dispc_mgr_pclk_rate
  122. dispc_set_tv_pclk
  123. dispc_core_clk_rate
  124. dispc_plane_pclk_rate
  125. dispc_plane_lclk_rate
  126. dispc_dump_clocks_channel
  127. dispc_dump_clocks
  128. dispc_dump_regs
  129. dispc_calc_clock_rates
  130. dispc_div_calc
  131. dispc_mgr_set_clock_div
  132. dispc_mgr_get_clock_div
  133. dispc_read_irqstatus
  134. dispc_clear_irqstatus
  135. dispc_read_irqenable
  136. dispc_write_irqenable
  137. dispc_enable_sidle
  138. dispc_disable_sidle
  139. _omap_dispc_initial_config
  140. dispc_get_features
  141. dispc_irq_handler
  142. dispc_request_irq
  143. dispc_free_irq
  144. dispc_bind
  145. dispc_unbind
  146. dispc_probe
  147. dispc_remove
  148. dispc_runtime_suspend
  149. dispc_runtime_resume
  150. dispc_init_platform_driver
  151. dispc_uninit_platform_driver

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

/* [<][>][^][v][top][bottom][index][help] */