linux/drivers/video/omap/dispc.c
<<
>>
Prefs
   1/*
   2 * OMAP2 display controller support
   3 *
   4 * Copyright (C) 2005 Nokia Corporation
   5 * Author: Imre Deak <imre.deak@nokia.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License as published by the
   9 * Free Software Foundation; either version 2 of the License, or (at your
  10 * option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License along
  18 * with this program; if not, write to the Free Software Foundation, Inc.,
  19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20 */
  21#include <linux/kernel.h>
  22#include <linux/dma-mapping.h>
  23#include <linux/mm.h>
  24#include <linux/vmalloc.h>
  25#include <linux/clk.h>
  26#include <linux/io.h>
  27#include <linux/platform_device.h>
  28#include <linux/slab.h>
  29
  30#include <plat/sram.h>
  31#include <plat/board.h>
  32
  33#include "omapfb.h"
  34#include "dispc.h"
  35
  36#define MODULE_NAME                     "dispc"
  37
  38#define DSS_BASE                        0x48050000
  39#define DSS_SYSCONFIG                   0x0010
  40
  41#define DISPC_BASE                      0x48050400
  42
  43/* DISPC common */
  44#define DISPC_REVISION                  0x0000
  45#define DISPC_SYSCONFIG                 0x0010
  46#define DISPC_SYSSTATUS                 0x0014
  47#define DISPC_IRQSTATUS                 0x0018
  48#define DISPC_IRQENABLE                 0x001C
  49#define DISPC_CONTROL                   0x0040
  50#define DISPC_CONFIG                    0x0044
  51#define DISPC_CAPABLE                   0x0048
  52#define DISPC_DEFAULT_COLOR0            0x004C
  53#define DISPC_DEFAULT_COLOR1            0x0050
  54#define DISPC_TRANS_COLOR0              0x0054
  55#define DISPC_TRANS_COLOR1              0x0058
  56#define DISPC_LINE_STATUS               0x005C
  57#define DISPC_LINE_NUMBER               0x0060
  58#define DISPC_TIMING_H                  0x0064
  59#define DISPC_TIMING_V                  0x0068
  60#define DISPC_POL_FREQ                  0x006C
  61#define DISPC_DIVISOR                   0x0070
  62#define DISPC_SIZE_DIG                  0x0078
  63#define DISPC_SIZE_LCD                  0x007C
  64
  65#define DISPC_DATA_CYCLE1               0x01D4
  66#define DISPC_DATA_CYCLE2               0x01D8
  67#define DISPC_DATA_CYCLE3               0x01DC
  68
  69/* DISPC GFX plane */
  70#define DISPC_GFX_BA0                   0x0080
  71#define DISPC_GFX_BA1                   0x0084
  72#define DISPC_GFX_POSITION              0x0088
  73#define DISPC_GFX_SIZE                  0x008C
  74#define DISPC_GFX_ATTRIBUTES            0x00A0
  75#define DISPC_GFX_FIFO_THRESHOLD        0x00A4
  76#define DISPC_GFX_FIFO_SIZE_STATUS      0x00A8
  77#define DISPC_GFX_ROW_INC               0x00AC
  78#define DISPC_GFX_PIXEL_INC             0x00B0
  79#define DISPC_GFX_WINDOW_SKIP           0x00B4
  80#define DISPC_GFX_TABLE_BA              0x00B8
  81
  82/* DISPC Video plane 1/2 */
  83#define DISPC_VID1_BASE                 0x00BC
  84#define DISPC_VID2_BASE                 0x014C
  85
  86/* Offsets into DISPC_VID1/2_BASE */
  87#define DISPC_VID_BA0                   0x0000
  88#define DISPC_VID_BA1                   0x0004
  89#define DISPC_VID_POSITION              0x0008
  90#define DISPC_VID_SIZE                  0x000C
  91#define DISPC_VID_ATTRIBUTES            0x0010
  92#define DISPC_VID_FIFO_THRESHOLD        0x0014
  93#define DISPC_VID_FIFO_SIZE_STATUS      0x0018
  94#define DISPC_VID_ROW_INC               0x001C
  95#define DISPC_VID_PIXEL_INC             0x0020
  96#define DISPC_VID_FIR                   0x0024
  97#define DISPC_VID_PICTURE_SIZE          0x0028
  98#define DISPC_VID_ACCU0                 0x002C
  99#define DISPC_VID_ACCU1                 0x0030
 100
 101/* 8 elements in 8 byte increments */
 102#define DISPC_VID_FIR_COEF_H0           0x0034
 103/* 8 elements in 8 byte increments */
 104#define DISPC_VID_FIR_COEF_HV0          0x0038
 105/* 5 elements in 4 byte increments */
 106#define DISPC_VID_CONV_COEF0            0x0074
 107
 108#define DISPC_IRQ_FRAMEMASK             0x0001
 109#define DISPC_IRQ_VSYNC                 0x0002
 110#define DISPC_IRQ_EVSYNC_EVEN           0x0004
 111#define DISPC_IRQ_EVSYNC_ODD            0x0008
 112#define DISPC_IRQ_ACBIAS_COUNT_STAT     0x0010
 113#define DISPC_IRQ_PROG_LINE_NUM         0x0020
 114#define DISPC_IRQ_GFX_FIFO_UNDERFLOW    0x0040
 115#define DISPC_IRQ_GFX_END_WIN           0x0080
 116#define DISPC_IRQ_PAL_GAMMA_MASK        0x0100
 117#define DISPC_IRQ_OCP_ERR               0x0200
 118#define DISPC_IRQ_VID1_FIFO_UNDERFLOW   0x0400
 119#define DISPC_IRQ_VID1_END_WIN          0x0800
 120#define DISPC_IRQ_VID2_FIFO_UNDERFLOW   0x1000
 121#define DISPC_IRQ_VID2_END_WIN          0x2000
 122#define DISPC_IRQ_SYNC_LOST             0x4000
 123
 124#define DISPC_IRQ_MASK_ALL              0x7fff
 125
 126#define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
 127                                             DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
 128                                             DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
 129                                             DISPC_IRQ_SYNC_LOST)
 130
 131#define RFBI_CONTROL                    0x48050040
 132
 133#define MAX_PALETTE_SIZE                (256 * 16)
 134
 135#define FLD_MASK(pos, len)      (((1 << len) - 1) << pos)
 136
 137#define MOD_REG_FLD(reg, mask, val) \
 138        dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));
 139
 140#define OMAP2_SRAM_START                0x40200000
 141/* Maximum size, in reality this is smaller if SRAM is partially locked. */
 142#define OMAP2_SRAM_SIZE                 0xa0000         /* 640k */
 143
 144/* We support the SDRAM / SRAM types. See OMAPFB_PLANE_MEMTYPE_* in omapfb.h */
 145#define DISPC_MEMTYPE_NUM               2
 146
 147#define RESMAP_SIZE(_page_cnt)                                          \
 148        ((_page_cnt + (sizeof(unsigned long) * 8) - 1) / 8)
 149#define RESMAP_PTR(_res_map, _page_nr)                                  \
 150        (((_res_map)->map) + (_page_nr) / (sizeof(unsigned long) * 8))
 151#define RESMAP_MASK(_page_nr)                                           \
 152        (1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1)))
 153
 154struct resmap {
 155        unsigned long   start;
 156        unsigned        page_cnt;
 157        unsigned long   *map;
 158};
 159
 160#define MAX_IRQ_HANDLERS            4
 161
 162static struct {
 163        void __iomem    *base;
 164
 165        struct omapfb_mem_desc  mem_desc;
 166        struct resmap           *res_map[DISPC_MEMTYPE_NUM];
 167        atomic_t                map_count[OMAPFB_PLANE_NUM];
 168
 169        dma_addr_t      palette_paddr;
 170        void            *palette_vaddr;
 171
 172        int             ext_mode;
 173
 174        struct {
 175                u32     irq_mask;
 176                void    (*callback)(void *);
 177                void    *data;
 178        } irq_handlers[MAX_IRQ_HANDLERS];
 179        struct completion       frame_done;
 180
 181        int             fir_hinc[OMAPFB_PLANE_NUM];
 182        int             fir_vinc[OMAPFB_PLANE_NUM];
 183
 184        struct clk      *dss_ick, *dss1_fck;
 185        struct clk      *dss_54m_fck;
 186
 187        enum omapfb_update_mode update_mode;
 188        struct omapfb_device    *fbdev;
 189
 190        struct omapfb_color_key color_key;
 191} dispc;
 192
 193static void enable_lcd_clocks(int enable);
 194
 195static void inline dispc_write_reg(int idx, u32 val)
 196{
 197        __raw_writel(val, dispc.base + idx);
 198}
 199
 200static u32 inline dispc_read_reg(int idx)
 201{
 202        u32 l = __raw_readl(dispc.base + idx);
 203        return l;
 204}
 205
 206/* Select RFBI or bypass mode */
 207static void enable_rfbi_mode(int enable)
 208{
 209        void __iomem *rfbi_control;
 210        u32 l;
 211
 212        l = dispc_read_reg(DISPC_CONTROL);
 213        /* Enable RFBI, GPIO0/1 */
 214        l &= ~((1 << 11) | (1 << 15) | (1 << 16));
 215        l |= enable ? (1 << 11) : 0;
 216        /* RFBI En: GPIO0/1=10  RFBI Dis: GPIO0/1=11 */
 217        l |= 1 << 15;
 218        l |= enable ? 0 : (1 << 16);
 219        dispc_write_reg(DISPC_CONTROL, l);
 220
 221        /* Set bypass mode in RFBI module */
 222        rfbi_control = ioremap(RFBI_CONTROL, SZ_1K);
 223        if (!rfbi_control) {
 224                pr_err("Unable to ioremap rfbi_control\n");
 225                return;
 226        }
 227        l = __raw_readl(rfbi_control);
 228        l |= enable ? 0 : (1 << 1);
 229        __raw_writel(l, rfbi_control);
 230        iounmap(rfbi_control);
 231}
 232
 233static void set_lcd_data_lines(int data_lines)
 234{
 235        u32 l;
 236        int code = 0;
 237
 238        switch (data_lines) {
 239        case 12:
 240                code = 0;
 241                break;
 242        case 16:
 243                code = 1;
 244                break;
 245        case 18:
 246                code = 2;
 247                break;
 248        case 24:
 249                code = 3;
 250                break;
 251        default:
 252                BUG();
 253        }
 254
 255        l = dispc_read_reg(DISPC_CONTROL);
 256        l &= ~(0x03 << 8);
 257        l |= code << 8;
 258        dispc_write_reg(DISPC_CONTROL, l);
 259}
 260
 261static void set_load_mode(int mode)
 262{
 263        BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY |
 264                        DISPC_LOAD_CLUT_ONCE_FRAME));
 265        MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);
 266}
 267
 268void omap_dispc_set_lcd_size(int x, int y)
 269{
 270        BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
 271        enable_lcd_clocks(1);
 272        MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11),
 273                        ((y - 1) << 16) | (x - 1));
 274        enable_lcd_clocks(0);
 275}
 276EXPORT_SYMBOL(omap_dispc_set_lcd_size);
 277
 278void omap_dispc_set_digit_size(int x, int y)
 279{
 280        BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
 281        enable_lcd_clocks(1);
 282        MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11),
 283                        ((y - 1) << 16) | (x - 1));
 284        enable_lcd_clocks(0);
 285}
 286EXPORT_SYMBOL(omap_dispc_set_digit_size);
 287
 288static void setup_plane_fifo(int plane, int ext_mode)
 289{
 290        const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
 291                                DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD,
 292                                DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD };
 293        const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
 294                                DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS,
 295                                DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS };
 296        int low, high;
 297        u32 l;
 298
 299        BUG_ON(plane > 2);
 300
 301        l = dispc_read_reg(fsz_reg[plane]);
 302        l &= FLD_MASK(0, 11);
 303        if (ext_mode) {
 304                low = l * 3 / 4;
 305                high = l;
 306        } else {
 307                low = l / 4;
 308                high = l * 3 / 4;
 309        }
 310        MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 12) | FLD_MASK(0, 12),
 311                        (high << 16) | low);
 312}
 313
 314void omap_dispc_enable_lcd_out(int enable)
 315{
 316        enable_lcd_clocks(1);
 317        MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0);
 318        enable_lcd_clocks(0);
 319}
 320EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
 321
 322void omap_dispc_enable_digit_out(int enable)
 323{
 324        enable_lcd_clocks(1);
 325        MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0);
 326        enable_lcd_clocks(0);
 327}
 328EXPORT_SYMBOL(omap_dispc_enable_digit_out);
 329
 330static inline int _setup_plane(int plane, int channel_out,
 331                                  u32 paddr, int screen_width,
 332                                  int pos_x, int pos_y, int width, int height,
 333                                  int color_mode)
 334{
 335        const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
 336                                DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
 337                                DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
 338        const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0,
 339                                DISPC_VID2_BASE + DISPC_VID_BA0 };
 340        const u32 ps_reg[] = { DISPC_GFX_POSITION,
 341                                DISPC_VID1_BASE + DISPC_VID_POSITION,
 342                                DISPC_VID2_BASE + DISPC_VID_POSITION };
 343        const u32 sz_reg[] = { DISPC_GFX_SIZE,
 344                                DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE,
 345                                DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE };
 346        const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
 347                                DISPC_VID1_BASE + DISPC_VID_ROW_INC,
 348                                DISPC_VID2_BASE + DISPC_VID_ROW_INC };
 349        const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
 350                                DISPC_VID2_BASE + DISPC_VID_SIZE };
 351
 352        int chout_shift, burst_shift;
 353        int chout_val;
 354        int color_code;
 355        int bpp;
 356        int cconv_en;
 357        int set_vsize;
 358        u32 l;
 359
 360#ifdef VERBOSE
 361        dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d"
 362                    " pos_x %d pos_y %d width %d height %d color_mode %d\n",
 363                    plane, channel_out, paddr, screen_width, pos_x, pos_y,
 364                    width, height, color_mode);
 365#endif
 366
 367        set_vsize = 0;
 368        switch (plane) {
 369        case OMAPFB_PLANE_GFX:
 370                burst_shift = 6;
 371                chout_shift = 8;
 372                break;
 373        case OMAPFB_PLANE_VID1:
 374        case OMAPFB_PLANE_VID2:
 375                burst_shift = 14;
 376                chout_shift = 16;
 377                set_vsize = 1;
 378                break;
 379        default:
 380                return -EINVAL;
 381        }
 382
 383        switch (channel_out) {
 384        case OMAPFB_CHANNEL_OUT_LCD:
 385                chout_val = 0;
 386                break;
 387        case OMAPFB_CHANNEL_OUT_DIGIT:
 388                chout_val = 1;
 389                break;
 390        default:
 391                return -EINVAL;
 392        }
 393
 394        cconv_en = 0;
 395        switch (color_mode) {
 396        case OMAPFB_COLOR_RGB565:
 397                color_code = DISPC_RGB_16_BPP;
 398                bpp = 16;
 399                break;
 400        case OMAPFB_COLOR_YUV422:
 401                if (plane == 0)
 402                        return -EINVAL;
 403                color_code = DISPC_UYVY_422;
 404                cconv_en = 1;
 405                bpp = 16;
 406                break;
 407        case OMAPFB_COLOR_YUY422:
 408                if (plane == 0)
 409                        return -EINVAL;
 410                color_code = DISPC_YUV2_422;
 411                cconv_en = 1;
 412                bpp = 16;
 413                break;
 414        default:
 415                return -EINVAL;
 416        }
 417
 418        l = dispc_read_reg(at_reg[plane]);
 419
 420        l &= ~(0x0f << 1);
 421        l |= color_code << 1;
 422        l &= ~(1 << 9);
 423        l |= cconv_en << 9;
 424
 425        l &= ~(0x03 << burst_shift);
 426        l |= DISPC_BURST_8x32 << burst_shift;
 427
 428        l &= ~(1 << chout_shift);
 429        l |= chout_val << chout_shift;
 430
 431        dispc_write_reg(at_reg[plane], l);
 432
 433        dispc_write_reg(ba_reg[plane], paddr);
 434        MOD_REG_FLD(ps_reg[plane],
 435                    FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
 436
 437        MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
 438                        ((height - 1) << 16) | (width - 1));
 439
 440        if (set_vsize) {
 441                /* Set video size if set_scale hasn't set it */
 442                if (!dispc.fir_vinc[plane])
 443                        MOD_REG_FLD(vs_reg[plane],
 444                                FLD_MASK(16, 11), (height - 1) << 16);
 445                if (!dispc.fir_hinc[plane])
 446                        MOD_REG_FLD(vs_reg[plane],
 447                                FLD_MASK(0, 11), width - 1);
 448        }
 449
 450        dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
 451
 452        return height * screen_width * bpp / 8;
 453}
 454
 455static int omap_dispc_setup_plane(int plane, int channel_out,
 456                                  unsigned long offset,
 457                                  int screen_width,
 458                                  int pos_x, int pos_y, int width, int height,
 459                                  int color_mode)
 460{
 461        u32 paddr;
 462        int r;
 463
 464        if ((unsigned)plane > dispc.mem_desc.region_cnt)
 465                return -EINVAL;
 466        paddr = dispc.mem_desc.region[plane].paddr + offset;
 467        enable_lcd_clocks(1);
 468        r = _setup_plane(plane, channel_out, paddr,
 469                        screen_width,
 470                        pos_x, pos_y, width, height, color_mode);
 471        enable_lcd_clocks(0);
 472        return r;
 473}
 474
 475static void write_firh_reg(int plane, int reg, u32 value)
 476{
 477        u32 base;
 478
 479        if (plane == 1)
 480                base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0;
 481        else
 482                base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0;
 483        dispc_write_reg(base + reg * 8, value);
 484}
 485
 486static void write_firhv_reg(int plane, int reg, u32 value)
 487{
 488        u32 base;
 489
 490        if (plane == 1)
 491                base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0;
 492        else
 493                base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0;
 494        dispc_write_reg(base + reg * 8, value);
 495}
 496
 497static void set_upsampling_coef_table(int plane)
 498{
 499        const u32 coef[][2] = {
 500                { 0x00800000, 0x00800000 },
 501                { 0x0D7CF800, 0x037B02FF },
 502                { 0x1E70F5FF, 0x0C6F05FE },
 503                { 0x335FF5FE, 0x205907FB },
 504                { 0xF74949F7, 0x00404000 },
 505                { 0xF55F33FB, 0x075920FE },
 506                { 0xF5701EFE, 0x056F0CFF },
 507                { 0xF87C0DFF, 0x027B0300 },
 508        };
 509        int i;
 510
 511        for (i = 0; i < 8; i++) {
 512                write_firh_reg(plane, i, coef[i][0]);
 513                write_firhv_reg(plane, i, coef[i][1]);
 514        }
 515}
 516
 517static int omap_dispc_set_scale(int plane,
 518                                int orig_width, int orig_height,
 519                                int out_width, int out_height)
 520{
 521        const u32 at_reg[]  = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
 522                                DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
 523        const u32 vs_reg[]  = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
 524                                DISPC_VID2_BASE + DISPC_VID_SIZE };
 525        const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR,
 526                                DISPC_VID2_BASE + DISPC_VID_FIR };
 527
 528        u32 l;
 529        int fir_hinc;
 530        int fir_vinc;
 531
 532        if ((unsigned)plane > OMAPFB_PLANE_NUM)
 533                return -ENODEV;
 534
 535        if (plane == OMAPFB_PLANE_GFX &&
 536            (out_width != orig_width || out_height != orig_height))
 537                return -EINVAL;
 538
 539        enable_lcd_clocks(1);
 540        if (orig_width < out_width) {
 541                /*
 542                 * Upsampling.
 543                 * Currently you can only scale both dimensions in one way.
 544                 */
 545                if (orig_height > out_height ||
 546                    orig_width * 8 < out_width ||
 547                    orig_height * 8 < out_height) {
 548                        enable_lcd_clocks(0);
 549                        return -EINVAL;
 550                }
 551                set_upsampling_coef_table(plane);
 552        } else if (orig_width > out_width) {
 553                /* Downsampling not yet supported
 554                */
 555
 556                enable_lcd_clocks(0);
 557                return -EINVAL;
 558        }
 559        if (!orig_width || orig_width == out_width)
 560                fir_hinc = 0;
 561        else
 562                fir_hinc = 1024 * orig_width / out_width;
 563        if (!orig_height || orig_height == out_height)
 564                fir_vinc = 0;
 565        else
 566                fir_vinc = 1024 * orig_height / out_height;
 567        dispc.fir_hinc[plane] = fir_hinc;
 568        dispc.fir_vinc[plane] = fir_vinc;
 569
 570        MOD_REG_FLD(fir_reg[plane],
 571                    FLD_MASK(16, 12) | FLD_MASK(0, 12),
 572                    ((fir_vinc & 4095) << 16) |
 573                    (fir_hinc & 4095));
 574
 575        dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "
 576                "orig_height %d fir_hinc  %d fir_vinc %d\n",
 577                out_width, out_height, orig_width, orig_height,
 578                fir_hinc, fir_vinc);
 579
 580        MOD_REG_FLD(vs_reg[plane],
 581                    FLD_MASK(16, 11) | FLD_MASK(0, 11),
 582                    ((out_height - 1) << 16) | (out_width - 1));
 583
 584        l = dispc_read_reg(at_reg[plane]);
 585        l &= ~(0x03 << 5);
 586        l |= fir_hinc ? (1 << 5) : 0;
 587        l |= fir_vinc ? (1 << 6) : 0;
 588        dispc_write_reg(at_reg[plane], l);
 589
 590        enable_lcd_clocks(0);
 591        return 0;
 592}
 593
 594static int omap_dispc_enable_plane(int plane, int enable)
 595{
 596        const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
 597                                DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
 598                                DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
 599        if ((unsigned int)plane > dispc.mem_desc.region_cnt)
 600                return -EINVAL;
 601
 602        enable_lcd_clocks(1);
 603        MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
 604        enable_lcd_clocks(0);
 605
 606        return 0;
 607}
 608
 609static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
 610{
 611        u32 df_reg, tr_reg;
 612        int shift, val;
 613
 614        switch (ck->channel_out) {
 615        case OMAPFB_CHANNEL_OUT_LCD:
 616                df_reg = DISPC_DEFAULT_COLOR0;
 617                tr_reg = DISPC_TRANS_COLOR0;
 618                shift = 10;
 619                break;
 620        case OMAPFB_CHANNEL_OUT_DIGIT:
 621                df_reg = DISPC_DEFAULT_COLOR1;
 622                tr_reg = DISPC_TRANS_COLOR1;
 623                shift = 12;
 624                break;
 625        default:
 626                return -EINVAL;
 627        }
 628        switch (ck->key_type) {
 629        case OMAPFB_COLOR_KEY_DISABLED:
 630                val = 0;
 631                break;
 632        case OMAPFB_COLOR_KEY_GFX_DST:
 633                val = 1;
 634                break;
 635        case OMAPFB_COLOR_KEY_VID_SRC:
 636                val = 3;
 637                break;
 638        default:
 639                return -EINVAL;
 640        }
 641        enable_lcd_clocks(1);
 642        MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);
 643
 644        if (val != 0)
 645                dispc_write_reg(tr_reg, ck->trans_key);
 646        dispc_write_reg(df_reg, ck->background);
 647        enable_lcd_clocks(0);
 648
 649        dispc.color_key = *ck;
 650
 651        return 0;
 652}
 653
 654static int omap_dispc_get_color_key(struct omapfb_color_key *ck)
 655{
 656        *ck = dispc.color_key;
 657        return 0;
 658}
 659
 660static void load_palette(void)
 661{
 662}
 663
 664static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
 665{
 666        int r = 0;
 667
 668        if (mode != dispc.update_mode) {
 669                switch (mode) {
 670                case OMAPFB_AUTO_UPDATE:
 671                case OMAPFB_MANUAL_UPDATE:
 672                        enable_lcd_clocks(1);
 673                        omap_dispc_enable_lcd_out(1);
 674                        dispc.update_mode = mode;
 675                        break;
 676                case OMAPFB_UPDATE_DISABLED:
 677                        init_completion(&dispc.frame_done);
 678                        omap_dispc_enable_lcd_out(0);
 679                        if (!wait_for_completion_timeout(&dispc.frame_done,
 680                                        msecs_to_jiffies(500))) {
 681                                dev_err(dispc.fbdev->dev,
 682                                         "timeout waiting for FRAME DONE\n");
 683                        }
 684                        dispc.update_mode = mode;
 685                        enable_lcd_clocks(0);
 686                        break;
 687                default:
 688                        r = -EINVAL;
 689                }
 690        }
 691
 692        return r;
 693}
 694
 695static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps)
 696{
 697        caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM;
 698        if (plane > 0)
 699                caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE;
 700        caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) |
 701                             (1 << OMAPFB_COLOR_YUV422) |
 702                             (1 << OMAPFB_COLOR_YUY422);
 703        if (plane == 0)
 704                caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) |
 705                                     (1 << OMAPFB_COLOR_CLUT_4BPP) |
 706                                     (1 << OMAPFB_COLOR_CLUT_2BPP) |
 707                                     (1 << OMAPFB_COLOR_CLUT_1BPP) |
 708                                     (1 << OMAPFB_COLOR_RGB444);
 709}
 710
 711static enum omapfb_update_mode omap_dispc_get_update_mode(void)
 712{
 713        return dispc.update_mode;
 714}
 715
 716static void setup_color_conv_coef(void)
 717{
 718        u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11);
 719        int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0;
 720        int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0;
 721        int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES;
 722        int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES;
 723        const struct color_conv_coef {
 724                int  ry,  rcr,  rcb,   gy,  gcr,  gcb,   by,  bcr,  bcb;
 725                int  full_range;
 726        }  ctbl_bt601_5 = {
 727                    298,  409,    0,  298, -208, -100,  298,    0,  517, 0,
 728        };
 729        const struct color_conv_coef *ct;
 730#define CVAL(x, y)      (((x & 2047) << 16) | (y & 2047))
 731
 732        ct = &ctbl_bt601_5;
 733
 734        MOD_REG_FLD(cf1_reg,            mask,   CVAL(ct->rcr, ct->ry));
 735        MOD_REG_FLD(cf1_reg + 4,        mask,   CVAL(ct->gy,  ct->rcb));
 736        MOD_REG_FLD(cf1_reg + 8,        mask,   CVAL(ct->gcb, ct->gcr));
 737        MOD_REG_FLD(cf1_reg + 12,       mask,   CVAL(ct->bcr, ct->by));
 738        MOD_REG_FLD(cf1_reg + 16,       mask,   CVAL(0,       ct->bcb));
 739
 740        MOD_REG_FLD(cf2_reg,            mask,   CVAL(ct->rcr, ct->ry));
 741        MOD_REG_FLD(cf2_reg + 4,        mask,   CVAL(ct->gy,  ct->rcb));
 742        MOD_REG_FLD(cf2_reg + 8,        mask,   CVAL(ct->gcb, ct->gcr));
 743        MOD_REG_FLD(cf2_reg + 12,       mask,   CVAL(ct->bcr, ct->by));
 744        MOD_REG_FLD(cf2_reg + 16,       mask,   CVAL(0,       ct->bcb));
 745#undef CVAL
 746
 747        MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range);
 748        MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range);
 749}
 750
 751static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
 752{
 753        unsigned long fck, lck;
 754
 755        *lck_div = 1;
 756        pck = max(1, pck);
 757        fck = clk_get_rate(dispc.dss1_fck);
 758        lck = fck;
 759        *pck_div = (lck + pck - 1) / pck;
 760        if (is_tft)
 761                *pck_div = max(2, *pck_div);
 762        else
 763                *pck_div = max(3, *pck_div);
 764        if (*pck_div > 255) {
 765                *pck_div = 255;
 766                lck = pck * *pck_div;
 767                *lck_div = fck / lck;
 768                BUG_ON(*lck_div < 1);
 769                if (*lck_div > 255) {
 770                        *lck_div = 255;
 771                        dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n",
 772                                 pck / 1000);
 773                }
 774        }
 775}
 776
 777static void set_lcd_tft_mode(int enable)
 778{
 779        u32 mask;
 780
 781        mask = 1 << 3;
 782        MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
 783}
 784
 785static void set_lcd_timings(void)
 786{
 787        u32 l;
 788        int lck_div, pck_div;
 789        struct lcd_panel *panel = dispc.fbdev->panel;
 790        int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
 791        unsigned long fck;
 792
 793        l = dispc_read_reg(DISPC_TIMING_H);
 794        l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
 795        l |= ( max(1, (min(64,  panel->hsw))) - 1 ) << 0;
 796        l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;
 797        l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;
 798        dispc_write_reg(DISPC_TIMING_H, l);
 799
 800        l = dispc_read_reg(DISPC_TIMING_V);
 801        l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
 802        l |= ( max(1, (min(64,  panel->vsw))) - 1 ) << 0;
 803        l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;
 804        l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;
 805        dispc_write_reg(DISPC_TIMING_V, l);
 806
 807        l = dispc_read_reg(DISPC_POL_FREQ);
 808        l &= ~FLD_MASK(12, 6);
 809        l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;
 810        l |= panel->acb & 0xff;
 811        dispc_write_reg(DISPC_POL_FREQ, l);
 812
 813        calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);
 814
 815        l = dispc_read_reg(DISPC_DIVISOR);
 816        l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));
 817        l |= (lck_div << 16) | (pck_div << 0);
 818        dispc_write_reg(DISPC_DIVISOR, l);
 819
 820        /* update panel info with the exact clock */
 821        fck = clk_get_rate(dispc.dss1_fck);
 822        panel->pixel_clock = fck / lck_div / pck_div / 1000;
 823}
 824
 825static void recalc_irq_mask(void)
 826{
 827        int i;
 828        unsigned long irq_mask = DISPC_IRQ_MASK_ERROR;
 829
 830        for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
 831                if (!dispc.irq_handlers[i].callback)
 832                        continue;
 833
 834                irq_mask |= dispc.irq_handlers[i].irq_mask;
 835        }
 836
 837        enable_lcd_clocks(1);
 838        MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
 839        enable_lcd_clocks(0);
 840}
 841
 842int omap_dispc_request_irq(unsigned long irq_mask, void (*callback)(void *data),
 843                           void *data)
 844{
 845        int i;
 846
 847        BUG_ON(callback == NULL);
 848
 849        for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
 850                if (dispc.irq_handlers[i].callback)
 851                        continue;
 852
 853                dispc.irq_handlers[i].irq_mask = irq_mask;
 854                dispc.irq_handlers[i].callback = callback;
 855                dispc.irq_handlers[i].data = data;
 856                recalc_irq_mask();
 857
 858                return 0;
 859        }
 860
 861        return -EBUSY;
 862}
 863EXPORT_SYMBOL(omap_dispc_request_irq);
 864
 865void omap_dispc_free_irq(unsigned long irq_mask, void (*callback)(void *data),
 866                         void *data)
 867{
 868        int i;
 869
 870        for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
 871                if (dispc.irq_handlers[i].callback == callback &&
 872                    dispc.irq_handlers[i].data == data) {
 873                        dispc.irq_handlers[i].irq_mask = 0;
 874                        dispc.irq_handlers[i].callback = NULL;
 875                        dispc.irq_handlers[i].data = NULL;
 876                        recalc_irq_mask();
 877                        return;
 878                }
 879        }
 880
 881        BUG();
 882}
 883EXPORT_SYMBOL(omap_dispc_free_irq);
 884
 885static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
 886{
 887        u32 stat;
 888        int i = 0;
 889
 890        enable_lcd_clocks(1);
 891
 892        stat = dispc_read_reg(DISPC_IRQSTATUS);
 893        if (stat & DISPC_IRQ_FRAMEMASK)
 894                complete(&dispc.frame_done);
 895
 896        if (stat & DISPC_IRQ_MASK_ERROR) {
 897                if (printk_ratelimit()) {
 898                        dev_err(dispc.fbdev->dev, "irq error status %04x\n",
 899                                stat & 0x7fff);
 900                }
 901        }
 902
 903        for (i = 0; i < MAX_IRQ_HANDLERS; i++) {
 904                if (unlikely(dispc.irq_handlers[i].callback &&
 905                             (stat & dispc.irq_handlers[i].irq_mask)))
 906                        dispc.irq_handlers[i].callback(
 907                                                dispc.irq_handlers[i].data);
 908        }
 909
 910        dispc_write_reg(DISPC_IRQSTATUS, stat);
 911
 912        enable_lcd_clocks(0);
 913
 914        return IRQ_HANDLED;
 915}
 916
 917static int get_dss_clocks(void)
 918{
 919        dispc.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick");
 920        if (IS_ERR(dispc.dss_ick)) {
 921                dev_err(dispc.fbdev->dev, "can't get ick\n");
 922                return PTR_ERR(dispc.dss_ick);
 923        }
 924
 925        dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck");
 926        if (IS_ERR(dispc.dss1_fck)) {
 927                dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
 928                clk_put(dispc.dss_ick);
 929                return PTR_ERR(dispc.dss1_fck);
 930        }
 931
 932        dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_fck");
 933        if (IS_ERR(dispc.dss_54m_fck)) {
 934                dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
 935                clk_put(dispc.dss_ick);
 936                clk_put(dispc.dss1_fck);
 937                return PTR_ERR(dispc.dss_54m_fck);
 938        }
 939
 940        return 0;
 941}
 942
 943static void put_dss_clocks(void)
 944{
 945        clk_put(dispc.dss_54m_fck);
 946        clk_put(dispc.dss1_fck);
 947        clk_put(dispc.dss_ick);
 948}
 949
 950static void enable_lcd_clocks(int enable)
 951{
 952        if (enable) {
 953                clk_enable(dispc.dss_ick);
 954                clk_enable(dispc.dss1_fck);
 955        } else {
 956                clk_disable(dispc.dss1_fck);
 957                clk_disable(dispc.dss_ick);
 958        }
 959}
 960
 961static void enable_digit_clocks(int enable)
 962{
 963        if (enable)
 964                clk_enable(dispc.dss_54m_fck);
 965        else
 966                clk_disable(dispc.dss_54m_fck);
 967}
 968
 969static void omap_dispc_suspend(void)
 970{
 971        if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
 972                init_completion(&dispc.frame_done);
 973                omap_dispc_enable_lcd_out(0);
 974                if (!wait_for_completion_timeout(&dispc.frame_done,
 975                                msecs_to_jiffies(500))) {
 976                        dev_err(dispc.fbdev->dev,
 977                                "timeout waiting for FRAME DONE\n");
 978                }
 979                enable_lcd_clocks(0);
 980        }
 981}
 982
 983static void omap_dispc_resume(void)
 984{
 985        if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
 986                enable_lcd_clocks(1);
 987                if (!dispc.ext_mode) {
 988                        set_lcd_timings();
 989                        load_palette();
 990                }
 991                omap_dispc_enable_lcd_out(1);
 992        }
 993}
 994
 995
 996static int omap_dispc_update_window(struct fb_info *fbi,
 997                                 struct omapfb_update_window *win,
 998                                 void (*complete_callback)(void *arg),
 999                                 void *complete_callback_data)
1000{
1001        return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
1002}
1003
1004static int mmap_kern(struct omapfb_mem_region *region)
1005{
1006        struct vm_struct        *kvma;
1007        struct vm_area_struct   vma;
1008        pgprot_t                pgprot;
1009        unsigned long           vaddr;
1010
1011        kvma = get_vm_area(region->size, VM_IOREMAP);
1012        if (kvma == NULL) {
1013                dev_err(dispc.fbdev->dev, "can't get kernel vm area\n");
1014                return -ENOMEM;
1015        }
1016        vma.vm_mm = &init_mm;
1017
1018        vaddr = (unsigned long)kvma->addr;
1019
1020        pgprot = pgprot_writecombine(pgprot_kernel);
1021        vma.vm_start = vaddr;
1022        vma.vm_end = vaddr + region->size;
1023        if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT,
1024                           region->size, pgprot) < 0) {
1025                dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n");
1026                return -EAGAIN;
1027        }
1028        region->vaddr = (void *)vaddr;
1029
1030        return 0;
1031}
1032
1033static void mmap_user_open(struct vm_area_struct *vma)
1034{
1035        int plane = (int)vma->vm_private_data;
1036
1037        atomic_inc(&dispc.map_count[plane]);
1038}
1039
1040static void mmap_user_close(struct vm_area_struct *vma)
1041{
1042        int plane = (int)vma->vm_private_data;
1043
1044        atomic_dec(&dispc.map_count[plane]);
1045}
1046
1047static const struct vm_operations_struct mmap_user_ops = {
1048        .open = mmap_user_open,
1049        .close = mmap_user_close,
1050};
1051
1052static int omap_dispc_mmap_user(struct fb_info *info,
1053                                struct vm_area_struct *vma)
1054{
1055        struct omapfb_plane_struct *plane = info->par;
1056        unsigned long off;
1057        unsigned long start;
1058        u32 len;
1059
1060        if (vma->vm_end - vma->vm_start == 0)
1061                return 0;
1062        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1063                return -EINVAL;
1064        off = vma->vm_pgoff << PAGE_SHIFT;
1065
1066        start = info->fix.smem_start;
1067        len = info->fix.smem_len;
1068        if (off >= len)
1069                return -EINVAL;
1070        if ((vma->vm_end - vma->vm_start + off) > len)
1071                return -EINVAL;
1072        off += start;
1073        vma->vm_pgoff = off >> PAGE_SHIFT;
1074        vma->vm_flags |= VM_IO | VM_RESERVED;
1075        vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1076        vma->vm_ops = &mmap_user_ops;
1077        vma->vm_private_data = (void *)plane->idx;
1078        if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1079                             vma->vm_end - vma->vm_start, vma->vm_page_prot))
1080                return -EAGAIN;
1081        /* vm_ops.open won't be called for mmap itself. */
1082        atomic_inc(&dispc.map_count[plane->idx]);
1083        return 0;
1084}
1085
1086static void unmap_kern(struct omapfb_mem_region *region)
1087{
1088        vunmap(region->vaddr);
1089}
1090
1091static int alloc_palette_ram(void)
1092{
1093        dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
1094                MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
1095        if (dispc.palette_vaddr == NULL) {
1096                dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n");
1097                return -ENOMEM;
1098        }
1099
1100        return 0;
1101}
1102
1103static void free_palette_ram(void)
1104{
1105        dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
1106                        dispc.palette_vaddr, dispc.palette_paddr);
1107}
1108
1109static int alloc_fbmem(struct omapfb_mem_region *region)
1110{
1111        region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
1112                        region->size, &region->paddr, GFP_KERNEL);
1113
1114        if (region->vaddr == NULL) {
1115                dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n");
1116                return -ENOMEM;
1117        }
1118
1119        return 0;
1120}
1121
1122static void free_fbmem(struct omapfb_mem_region *region)
1123{
1124        dma_free_writecombine(dispc.fbdev->dev, region->size,
1125                              region->vaddr, region->paddr);
1126}
1127
1128static struct resmap *init_resmap(unsigned long start, size_t size)
1129{
1130        unsigned page_cnt;
1131        struct resmap *res_map;
1132
1133        page_cnt = PAGE_ALIGN(size) / PAGE_SIZE;
1134        res_map =
1135            kzalloc(sizeof(struct resmap) + RESMAP_SIZE(page_cnt), GFP_KERNEL);
1136        if (res_map == NULL)
1137                return NULL;
1138        res_map->start = start;
1139        res_map->page_cnt = page_cnt;
1140        res_map->map = (unsigned long *)(res_map + 1);
1141        return res_map;
1142}
1143
1144static void cleanup_resmap(struct resmap *res_map)
1145{
1146        kfree(res_map);
1147}
1148
1149static inline int resmap_mem_type(unsigned long start)
1150{
1151        if (start >= OMAP2_SRAM_START &&
1152            start < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
1153                return OMAPFB_MEMTYPE_SRAM;
1154        else
1155                return OMAPFB_MEMTYPE_SDRAM;
1156}
1157
1158static inline int resmap_page_reserved(struct resmap *res_map, unsigned page_nr)
1159{
1160        return *RESMAP_PTR(res_map, page_nr) & RESMAP_MASK(page_nr) ? 1 : 0;
1161}
1162
1163static inline void resmap_reserve_page(struct resmap *res_map, unsigned page_nr)
1164{
1165        BUG_ON(resmap_page_reserved(res_map, page_nr));
1166        *RESMAP_PTR(res_map, page_nr) |= RESMAP_MASK(page_nr);
1167}
1168
1169static inline void resmap_free_page(struct resmap *res_map, unsigned page_nr)
1170{
1171        BUG_ON(!resmap_page_reserved(res_map, page_nr));
1172        *RESMAP_PTR(res_map, page_nr) &= ~RESMAP_MASK(page_nr);
1173}
1174
1175static void resmap_reserve_region(unsigned long start, size_t size)
1176{
1177
1178        struct resmap   *res_map;
1179        unsigned        start_page;
1180        unsigned        end_page;
1181        int             mtype;
1182        unsigned        i;
1183
1184        mtype = resmap_mem_type(start);
1185        res_map = dispc.res_map[mtype];
1186        dev_dbg(dispc.fbdev->dev, "reserve mem type %d start %08lx size %d\n",
1187                mtype, start, size);
1188        start_page = (start - res_map->start) / PAGE_SIZE;
1189        end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE;
1190        for (i = start_page; i < end_page; i++)
1191                resmap_reserve_page(res_map, i);
1192}
1193
1194static void resmap_free_region(unsigned long start, size_t size)
1195{
1196        struct resmap   *res_map;
1197        unsigned        start_page;
1198        unsigned        end_page;
1199        unsigned        i;
1200        int             mtype;
1201
1202        mtype = resmap_mem_type(start);
1203        res_map = dispc.res_map[mtype];
1204        dev_dbg(dispc.fbdev->dev, "free mem type %d start %08lx size %d\n",
1205                mtype, start, size);
1206        start_page = (start - res_map->start) / PAGE_SIZE;
1207        end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE;
1208        for (i = start_page; i < end_page; i++)
1209                resmap_free_page(res_map, i);
1210}
1211
1212static unsigned long resmap_alloc_region(int mtype, size_t size)
1213{
1214        unsigned i;
1215        unsigned total;
1216        unsigned start_page;
1217        unsigned long start;
1218        struct resmap *res_map = dispc.res_map[mtype];
1219
1220        BUG_ON(mtype >= DISPC_MEMTYPE_NUM || res_map == NULL || !size);
1221
1222        size = PAGE_ALIGN(size) / PAGE_SIZE;
1223        start_page = 0;
1224        total = 0;
1225        for (i = 0; i < res_map->page_cnt; i++) {
1226                if (resmap_page_reserved(res_map, i)) {
1227                        start_page = i + 1;
1228                        total = 0;
1229                } else if (++total == size)
1230                        break;
1231        }
1232        if (total < size)
1233                return 0;
1234
1235        start = res_map->start + start_page * PAGE_SIZE;
1236        resmap_reserve_region(start, size * PAGE_SIZE);
1237
1238        return start;
1239}
1240
1241/* Note that this will only work for user mappings, we don't deal with
1242 * kernel mappings here, so fbcon will keep using the old region.
1243 */
1244static int omap_dispc_setup_mem(int plane, size_t size, int mem_type,
1245                                unsigned long *paddr)
1246{
1247        struct omapfb_mem_region *rg;
1248        unsigned long new_addr = 0;
1249
1250        if ((unsigned)plane > dispc.mem_desc.region_cnt)
1251                return -EINVAL;
1252        if (mem_type >= DISPC_MEMTYPE_NUM)
1253                return -EINVAL;
1254        if (dispc.res_map[mem_type] == NULL)
1255                return -ENOMEM;
1256        rg = &dispc.mem_desc.region[plane];
1257        if (size == rg->size && mem_type == rg->type)
1258                return 0;
1259        if (atomic_read(&dispc.map_count[plane]))
1260                return -EBUSY;
1261        if (rg->size != 0)
1262                resmap_free_region(rg->paddr, rg->size);
1263        if (size != 0) {
1264                new_addr = resmap_alloc_region(mem_type, size);
1265                if (!new_addr) {
1266                        /* Reallocate old region. */
1267                        resmap_reserve_region(rg->paddr, rg->size);
1268                        return -ENOMEM;
1269                }
1270        }
1271        rg->paddr = new_addr;
1272        rg->size = size;
1273        rg->type = mem_type;
1274
1275        *paddr = new_addr;
1276
1277        return 0;
1278}
1279
1280static int setup_fbmem(struct omapfb_mem_desc *req_md)
1281{
1282        struct omapfb_mem_region        *rg;
1283        int i;
1284        int r;
1285        unsigned long                   mem_start[DISPC_MEMTYPE_NUM];
1286        unsigned long                   mem_end[DISPC_MEMTYPE_NUM];
1287
1288        if (!req_md->region_cnt) {
1289                dev_err(dispc.fbdev->dev, "no memory regions defined\n");
1290                return -ENOENT;
1291        }
1292
1293        rg = &req_md->region[0];
1294        memset(mem_start, 0xff, sizeof(mem_start));
1295        memset(mem_end, 0, sizeof(mem_end));
1296
1297        for (i = 0; i < req_md->region_cnt; i++, rg++) {
1298                int mtype;
1299                if (rg->paddr) {
1300                        rg->alloc = 0;
1301                        if (rg->vaddr == NULL) {
1302                                rg->map = 1;
1303                                if ((r = mmap_kern(rg)) < 0)
1304                                        return r;
1305                        }
1306                } else {
1307                        if (rg->type != OMAPFB_MEMTYPE_SDRAM) {
1308                                dev_err(dispc.fbdev->dev,
1309                                        "unsupported memory type\n");
1310                                return -EINVAL;
1311                        }
1312                        rg->alloc = rg->map = 1;
1313                        if ((r = alloc_fbmem(rg)) < 0)
1314                                return r;
1315                }
1316                mtype = rg->type;
1317
1318                if (rg->paddr < mem_start[mtype])
1319                        mem_start[mtype] = rg->paddr;
1320                if (rg->paddr + rg->size > mem_end[mtype])
1321                        mem_end[mtype] = rg->paddr + rg->size;
1322        }
1323
1324        for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
1325                unsigned long start;
1326                size_t size;
1327                if (mem_end[i] == 0)
1328                        continue;
1329                start = mem_start[i];
1330                size = mem_end[i] - start;
1331                dispc.res_map[i] = init_resmap(start, size);
1332                r = -ENOMEM;
1333                if (dispc.res_map[i] == NULL)
1334                        goto fail;
1335                /* Initial state is that everything is reserved. This
1336                 * includes possible holes as well, which will never be
1337                 * freed.
1338                 */
1339                resmap_reserve_region(start, size);
1340        }
1341
1342        dispc.mem_desc = *req_md;
1343
1344        return 0;
1345fail:
1346        for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
1347                if (dispc.res_map[i] != NULL)
1348                        cleanup_resmap(dispc.res_map[i]);
1349        }
1350        return r;
1351}
1352
1353static void cleanup_fbmem(void)
1354{
1355        struct omapfb_mem_region *rg;
1356        int i;
1357
1358        for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
1359                if (dispc.res_map[i] != NULL)
1360                        cleanup_resmap(dispc.res_map[i]);
1361        }
1362        rg = &dispc.mem_desc.region[0];
1363        for (i = 0; i < dispc.mem_desc.region_cnt; i++, rg++) {
1364                if (rg->alloc)
1365                        free_fbmem(rg);
1366                else {
1367                        if (rg->map)
1368                                unmap_kern(rg);
1369                }
1370        }
1371}
1372
1373static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
1374                           struct omapfb_mem_desc *req_vram)
1375{
1376        int r;
1377        u32 l;
1378        struct lcd_panel *panel = fbdev->panel;
1379        void __iomem *ram_fw_base;
1380        int tmo = 10000;
1381        int skip_init = 0;
1382        int i;
1383
1384        memset(&dispc, 0, sizeof(dispc));
1385
1386        dispc.base = ioremap(DISPC_BASE, SZ_1K);
1387        if (!dispc.base) {
1388                dev_err(fbdev->dev, "can't ioremap DISPC\n");
1389                return -ENOMEM;
1390        }
1391
1392        dispc.fbdev = fbdev;
1393        dispc.ext_mode = ext_mode;
1394
1395        init_completion(&dispc.frame_done);
1396
1397        if ((r = get_dss_clocks()) < 0)
1398                goto fail0;
1399
1400        enable_lcd_clocks(1);
1401
1402#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
1403        l = dispc_read_reg(DISPC_CONTROL);
1404        /* LCD enabled ? */
1405        if (l & 1) {
1406                pr_info("omapfb: skipping hardware initialization\n");
1407                skip_init = 1;
1408        }
1409#endif
1410
1411        if (!skip_init) {
1412                /* Reset monitoring works only w/ the 54M clk */
1413                enable_digit_clocks(1);
1414
1415                /* Soft reset */
1416                MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
1417
1418                while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
1419                        if (!--tmo) {
1420                                dev_err(dispc.fbdev->dev, "soft reset failed\n");
1421                                r = -ENODEV;
1422                                enable_digit_clocks(0);
1423                                goto fail1;
1424                        }
1425                }
1426
1427                enable_digit_clocks(0);
1428        }
1429
1430        /* Enable smart standby/idle, autoidle and wakeup */
1431        l = dispc_read_reg(DISPC_SYSCONFIG);
1432        l &= ~((3 << 12) | (3 << 3));
1433        l |= (2 << 12) | (2 << 3) | (1 << 2) | (1 << 0);
1434        dispc_write_reg(DISPC_SYSCONFIG, l);
1435        omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG);
1436
1437        /* Set functional clock autogating */
1438        l = dispc_read_reg(DISPC_CONFIG);
1439        l |= 1 << 9;
1440        dispc_write_reg(DISPC_CONFIG, l);
1441
1442        l = dispc_read_reg(DISPC_IRQSTATUS);
1443        dispc_write_reg(DISPC_IRQSTATUS, l);
1444
1445        recalc_irq_mask();
1446
1447        if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
1448                           0, MODULE_NAME, fbdev)) < 0) {
1449                dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n");
1450                goto fail1;
1451        }
1452
1453        /* L3 firewall setting: enable access to OCM RAM */
1454        ram_fw_base = ioremap(0x68005000, SZ_1K);
1455        if (!ram_fw_base) {
1456                dev_err(dispc.fbdev->dev, "Cannot ioremap to enable OCM RAM\n");
1457                goto fail1;
1458        }
1459        __raw_writel(0x402000b0, ram_fw_base + 0xa0);
1460        iounmap(ram_fw_base);
1461
1462        if ((r = alloc_palette_ram()) < 0)
1463                goto fail2;
1464
1465        if ((r = setup_fbmem(req_vram)) < 0)
1466                goto fail3;
1467
1468        if (!skip_init) {
1469                for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
1470                        memset(dispc.mem_desc.region[i].vaddr, 0,
1471                                dispc.mem_desc.region[i].size);
1472                }
1473
1474                /* Set logic clock to fck, pixel clock to fck/2 for now */
1475                MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
1476                MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
1477
1478                setup_plane_fifo(0, ext_mode);
1479                setup_plane_fifo(1, ext_mode);
1480                setup_plane_fifo(2, ext_mode);
1481
1482                setup_color_conv_coef();
1483
1484                set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
1485                set_load_mode(DISPC_LOAD_FRAME_ONLY);
1486
1487                if (!ext_mode) {
1488                        set_lcd_data_lines(panel->data_lines);
1489                        omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
1490                        set_lcd_timings();
1491                } else
1492                        set_lcd_data_lines(panel->bpp);
1493                enable_rfbi_mode(ext_mode);
1494        }
1495
1496        l = dispc_read_reg(DISPC_REVISION);
1497        pr_info("omapfb: DISPC version %d.%d initialized\n",
1498                 l >> 4 & 0x0f, l & 0x0f);
1499        enable_lcd_clocks(0);
1500
1501        return 0;
1502fail3:
1503        free_palette_ram();
1504fail2:
1505        free_irq(INT_24XX_DSS_IRQ, fbdev);
1506fail1:
1507        enable_lcd_clocks(0);
1508        put_dss_clocks();
1509fail0:
1510        iounmap(dispc.base);
1511        return r;
1512}
1513
1514static void omap_dispc_cleanup(void)
1515{
1516        int i;
1517
1518        omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED);
1519        /* This will also disable clocks that are on */
1520        for (i = 0; i < dispc.mem_desc.region_cnt; i++)
1521                omap_dispc_enable_plane(i, 0);
1522        cleanup_fbmem();
1523        free_palette_ram();
1524        free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
1525        put_dss_clocks();
1526        iounmap(dispc.base);
1527}
1528
1529const struct lcd_ctrl omap2_int_ctrl = {
1530        .name                   = "internal",
1531        .init                   = omap_dispc_init,
1532        .cleanup                = omap_dispc_cleanup,
1533        .get_caps               = omap_dispc_get_caps,
1534        .set_update_mode        = omap_dispc_set_update_mode,
1535        .get_update_mode        = omap_dispc_get_update_mode,
1536        .update_window          = omap_dispc_update_window,
1537        .suspend                = omap_dispc_suspend,
1538        .resume                 = omap_dispc_resume,
1539        .setup_plane            = omap_dispc_setup_plane,
1540        .setup_mem              = omap_dispc_setup_mem,
1541        .set_scale              = omap_dispc_set_scale,
1542        .enable_plane           = omap_dispc_enable_plane,
1543        .set_color_key          = omap_dispc_set_color_key,
1544        .get_color_key          = omap_dispc_get_color_key,
1545        .mmap                   = omap_dispc_mmap_user,
1546};
1547