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