linux/include/linux/amba/clcd.h
<<
>>
Prefs
   1/*
   2 * linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel.
   3 *
   4 * David A Rusling
   5 *
   6 * Copyright (C) 2001 ARM Limited
   7 *
   8 * This file is subject to the terms and conditions of the GNU General Public
   9 * License.  See the file COPYING in the main directory of this archive
  10 * for more details.
  11 */
  12#include <linux/fb.h>
  13
  14/*
  15 * CLCD Controller Internal Register addresses
  16 */
  17#define CLCD_TIM0               0x00000000
  18#define CLCD_TIM1               0x00000004
  19#define CLCD_TIM2               0x00000008
  20#define CLCD_TIM3               0x0000000c
  21#define CLCD_UBAS               0x00000010
  22#define CLCD_LBAS               0x00000014
  23
  24#if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW)
  25#define CLCD_IENB               0x00000018
  26#define CLCD_CNTL               0x0000001c
  27#else
  28/*
  29 * Someone rearranged these two registers on the Versatile
  30 * platform...
  31 */
  32#define CLCD_IENB               0x0000001c
  33#define CLCD_CNTL               0x00000018
  34#endif
  35
  36#define CLCD_STAT               0x00000020
  37#define CLCD_INTR               0x00000024
  38#define CLCD_UCUR               0x00000028
  39#define CLCD_LCUR               0x0000002C
  40#define CLCD_PALL               0x00000200
  41#define CLCD_PALETTE            0x00000200
  42
  43#define TIM2_CLKSEL             (1 << 5)
  44#define TIM2_IVS                (1 << 11)
  45#define TIM2_IHS                (1 << 12)
  46#define TIM2_IPC                (1 << 13)
  47#define TIM2_IOE                (1 << 14)
  48#define TIM2_BCD                (1 << 26)
  49
  50#define CNTL_LCDEN              (1 << 0)
  51#define CNTL_LCDBPP1            (0 << 1)
  52#define CNTL_LCDBPP2            (1 << 1)
  53#define CNTL_LCDBPP4            (2 << 1)
  54#define CNTL_LCDBPP8            (3 << 1)
  55#define CNTL_LCDBPP16           (4 << 1)
  56#define CNTL_LCDBPP16_565       (6 << 1)
  57#define CNTL_LCDBPP24           (5 << 1)
  58#define CNTL_LCDBW              (1 << 4)
  59#define CNTL_LCDTFT             (1 << 5)
  60#define CNTL_LCDMONO8           (1 << 6)
  61#define CNTL_LCDDUAL            (1 << 7)
  62#define CNTL_BGR                (1 << 8)
  63#define CNTL_BEBO               (1 << 9)
  64#define CNTL_BEPO               (1 << 10)
  65#define CNTL_LCDPWR             (1 << 11)
  66#define CNTL_LCDVCOMP(x)        ((x) << 12)
  67#define CNTL_LDMAFIFOTIME       (1 << 15)
  68#define CNTL_WATERMARK          (1 << 16)
  69
  70struct clcd_panel {
  71        struct fb_videomode     mode;
  72        signed short            width;  /* width in mm */
  73        signed short            height; /* height in mm */
  74        u32                     tim2;
  75        u32                     tim3;
  76        u32                     cntl;
  77        unsigned int            bpp:8,
  78                                fixedtimings:1,
  79                                grayscale:1;
  80        unsigned int            connector;
  81};
  82
  83struct clcd_regs {
  84        u32                     tim0;
  85        u32                     tim1;
  86        u32                     tim2;
  87        u32                     tim3;
  88        u32                     cntl;
  89        unsigned long           pixclock;
  90};
  91
  92struct clcd_fb;
  93
  94/*
  95 * the board-type specific routines
  96 */
  97struct clcd_board {
  98        const char *name;
  99
 100        /*
 101         * Optional.  Check whether the var structure is acceptable
 102         * for this display.
 103         */
 104        int     (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var);
 105
 106        /*
 107         * Compulsary.  Decode fb->fb.var into regs->*.  In the case of
 108         * fixed timing, set regs->* to the register values required.
 109         */
 110        void    (*decode)(struct clcd_fb *fb, struct clcd_regs *regs);
 111
 112        /*
 113         * Optional.  Disable any extra display hardware.
 114         */
 115        void    (*disable)(struct clcd_fb *);
 116
 117        /*
 118         * Optional.  Enable any extra display hardware.
 119         */
 120        void    (*enable)(struct clcd_fb *);
 121
 122        /*
 123         * Setup platform specific parts of CLCD driver
 124         */
 125        int     (*setup)(struct clcd_fb *);
 126
 127        /*
 128         * mmap the framebuffer memory
 129         */
 130        int     (*mmap)(struct clcd_fb *, struct vm_area_struct *);
 131
 132        /*
 133         * Remove platform specific parts of CLCD driver
 134         */
 135        void    (*remove)(struct clcd_fb *);
 136};
 137
 138struct amba_device;
 139struct clk;
 140
 141/* this data structure describes each frame buffer device we find */
 142struct clcd_fb {
 143        struct fb_info          fb;
 144        struct amba_device      *dev;
 145        struct clk              *clk;
 146        struct clcd_panel       *panel;
 147        struct clcd_board       *board;
 148        void                    *board_data;
 149        void __iomem            *regs;
 150        u32                     clcd_cntl;
 151        u32                     cmap[16];
 152};
 153
 154static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
 155{
 156        u32 val, cpl;
 157
 158        /*
 159         * Program the CLCD controller registers and start the CLCD
 160         */
 161        val = ((fb->fb.var.xres / 16) - 1) << 2;
 162        val |= (fb->fb.var.hsync_len - 1) << 8;
 163        val |= (fb->fb.var.right_margin - 1) << 16;
 164        val |= (fb->fb.var.left_margin - 1) << 24;
 165        regs->tim0 = val;
 166
 167        val = fb->fb.var.yres;
 168        if (fb->panel->cntl & CNTL_LCDDUAL)
 169                val /= 2;
 170        val -= 1;
 171        val |= (fb->fb.var.vsync_len - 1) << 10;
 172        val |= fb->fb.var.lower_margin << 16;
 173        val |= fb->fb.var.upper_margin << 24;
 174        regs->tim1 = val;
 175
 176        val = fb->panel->tim2;
 177        val |= fb->fb.var.sync & FB_SYNC_HOR_HIGH_ACT  ? 0 : TIM2_IHS;
 178        val |= fb->fb.var.sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
 179
 180        cpl = fb->fb.var.xres_virtual;
 181        if (fb->panel->cntl & CNTL_LCDTFT)        /* TFT */
 182                /* / 1 */;
 183        else if (!fb->fb.var.grayscale)           /* STN color */
 184                cpl = cpl * 8 / 3;
 185        else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */
 186                cpl /= 8;
 187        else                                      /* STN monochrome, 4bit */
 188                cpl /= 4;
 189
 190        regs->tim2 = val | ((cpl - 1) << 16);
 191
 192        regs->tim3 = fb->panel->tim3;
 193
 194        val = fb->panel->cntl;
 195        if (fb->fb.var.grayscale)
 196                val |= CNTL_LCDBW;
 197
 198        switch (fb->fb.var.bits_per_pixel) {
 199        case 1:
 200                val |= CNTL_LCDBPP1;
 201                break;
 202        case 2:
 203                val |= CNTL_LCDBPP2;
 204                break;
 205        case 4:
 206                val |= CNTL_LCDBPP4;
 207                break;
 208        case 8:
 209                val |= CNTL_LCDBPP8;
 210                break;
 211        case 16:
 212                /*
 213                 * PL110 cannot choose between 5551 and 565 modes in
 214                 * its control register
 215                 */
 216                if ((fb->dev->periphid & 0x000fffff) == 0x00041110)
 217                        val |= CNTL_LCDBPP16;
 218                else if (fb->fb.var.green.length == 5)
 219                        val |= CNTL_LCDBPP16;
 220                else
 221                        val |= CNTL_LCDBPP16_565;
 222                break;
 223        case 32:
 224                val |= CNTL_LCDBPP24;
 225                break;
 226        }
 227
 228        regs->cntl = val;
 229        regs->pixclock = fb->fb.var.pixclock;
 230}
 231
 232static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
 233{
 234        var->xres_virtual = var->xres = (var->xres + 15) & ~15;
 235        var->yres_virtual = var->yres = (var->yres + 1) & ~1;
 236
 237#define CHECK(e,l,h) (var->e < l || var->e > h)
 238        if (CHECK(right_margin, (5+1), 256) ||  /* back porch */
 239            CHECK(left_margin, (5+1), 256) ||   /* front porch */
 240            CHECK(hsync_len, (5+1), 256) ||
 241            var->xres > 4096 ||
 242            var->lower_margin > 255 ||          /* back porch */
 243            var->upper_margin > 255 ||          /* front porch */
 244            var->vsync_len > 32 ||
 245            var->yres > 1024)
 246                return -EINVAL;
 247#undef CHECK
 248
 249        /* single panel mode: PCD = max(PCD, 1) */
 250        /* dual panel mode: PCD = max(PCD, 5) */
 251
 252        /*
 253         * You can't change the grayscale setting, and
 254         * we can only do non-interlaced video.
 255         */
 256        if (var->grayscale != fb->fb.var.grayscale ||
 257            (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
 258                return -EINVAL;
 259
 260#define CHECK(e) (var->e != fb->fb.var.e)
 261        if (fb->panel->fixedtimings &&
 262            (CHECK(xres)                ||
 263             CHECK(yres)                ||
 264             CHECK(bits_per_pixel)      ||
 265             CHECK(pixclock)            ||
 266             CHECK(left_margin)         ||
 267             CHECK(right_margin)        ||
 268             CHECK(upper_margin)        ||
 269             CHECK(lower_margin)        ||
 270             CHECK(hsync_len)           ||
 271             CHECK(vsync_len)           ||
 272             CHECK(sync)))
 273                return -EINVAL;
 274#undef CHECK
 275
 276        var->nonstd = 0;
 277        var->accel_flags = 0;
 278
 279        return 0;
 280}
 281