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