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