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