Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel.
0003  *
0004  * David A Rusling
0005  *
0006  * Copyright (C) 2001 ARM Limited
0007  *
0008  * This file is subject to the terms and conditions of the GNU General Public
0009  * License.  See the file COPYING in the main directory of this archive
0010  * for more details.
0011  */
0012 #include <linux/fb.h>
0013 #include <linux/amba/clcd-regs.h>
0014 
0015 enum {
0016     /* individual formats */
0017     CLCD_CAP_RGB444     = (1 << 0),
0018     CLCD_CAP_RGB5551    = (1 << 1),
0019     CLCD_CAP_RGB565     = (1 << 2),
0020     CLCD_CAP_RGB888     = (1 << 3),
0021     CLCD_CAP_BGR444     = (1 << 4),
0022     CLCD_CAP_BGR5551    = (1 << 5),
0023     CLCD_CAP_BGR565     = (1 << 6),
0024     CLCD_CAP_BGR888     = (1 << 7),
0025 
0026     /* connection layouts */
0027     CLCD_CAP_444        = CLCD_CAP_RGB444 | CLCD_CAP_BGR444,
0028     CLCD_CAP_5551       = CLCD_CAP_RGB5551 | CLCD_CAP_BGR5551,
0029     CLCD_CAP_565        = CLCD_CAP_RGB565 | CLCD_CAP_BGR565,
0030     CLCD_CAP_888        = CLCD_CAP_RGB888 | CLCD_CAP_BGR888,
0031 
0032     /* red/blue ordering */
0033     CLCD_CAP_RGB        = CLCD_CAP_RGB444 | CLCD_CAP_RGB5551 |
0034                   CLCD_CAP_RGB565 | CLCD_CAP_RGB888,
0035     CLCD_CAP_BGR        = CLCD_CAP_BGR444 | CLCD_CAP_BGR5551 |
0036                   CLCD_CAP_BGR565 | CLCD_CAP_BGR888,
0037 
0038     CLCD_CAP_ALL        = CLCD_CAP_BGR | CLCD_CAP_RGB,
0039 };
0040 
0041 struct backlight_device;
0042 
0043 struct clcd_panel {
0044     struct fb_videomode mode;
0045     signed short        width;  /* width in mm */
0046     signed short        height; /* height in mm */
0047     u32         tim2;
0048     u32         tim3;
0049     u32         cntl;
0050     u32         caps;
0051     unsigned int        bpp:8,
0052                 fixedtimings:1,
0053                 grayscale:1;
0054     unsigned int        connector;
0055     struct backlight_device *backlight;
0056     /*
0057      * If the B/R lines are switched between the CLCD
0058      * and the panel we need to know this and not try to
0059      * compensate with the BGR bit in the control register.
0060      */
0061     bool            bgr_connection;
0062 };
0063 
0064 struct clcd_regs {
0065     u32         tim0;
0066     u32         tim1;
0067     u32         tim2;
0068     u32         tim3;
0069     u32         cntl;
0070     unsigned long       pixclock;
0071 };
0072 
0073 struct clcd_fb;
0074 
0075 /*
0076  * the board-type specific routines
0077  */
0078 struct clcd_board {
0079     const char *name;
0080 
0081     /*
0082      * Optional.  Hardware capability flags.
0083      */
0084     u32 caps;
0085 
0086     /*
0087      * Optional.  Check whether the var structure is acceptable
0088      * for this display.
0089      */
0090     int (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var);
0091 
0092     /*
0093      * Compulsory.  Decode fb->fb.var into regs->*.  In the case of
0094      * fixed timing, set regs->* to the register values required.
0095      */
0096     void    (*decode)(struct clcd_fb *fb, struct clcd_regs *regs);
0097 
0098     /*
0099      * Optional.  Disable any extra display hardware.
0100      */
0101     void    (*disable)(struct clcd_fb *);
0102 
0103     /*
0104      * Optional.  Enable any extra display hardware.
0105      */
0106     void    (*enable)(struct clcd_fb *);
0107 
0108     /*
0109      * Setup platform specific parts of CLCD driver
0110      */
0111     int (*setup)(struct clcd_fb *);
0112 
0113     /*
0114      * mmap the framebuffer memory
0115      */
0116     int (*mmap)(struct clcd_fb *, struct vm_area_struct *);
0117 
0118     /*
0119      * Remove platform specific parts of CLCD driver
0120      */
0121     void    (*remove)(struct clcd_fb *);
0122 };
0123 
0124 struct amba_device;
0125 struct clk;
0126 
0127 /* this data structure describes each frame buffer device we find */
0128 struct clcd_fb {
0129     struct fb_info      fb;
0130     struct amba_device  *dev;
0131     struct clk      *clk;
0132     struct clcd_panel   *panel;
0133     struct clcd_board   *board;
0134     void            *board_data;
0135     void __iomem        *regs;
0136     u16         off_ienb;
0137     u16         off_cntl;
0138     u32         clcd_cntl;
0139     u32         cmap[16];
0140     bool            clk_enabled;
0141 };
0142 
0143 static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
0144 {
0145     struct fb_var_screeninfo *var = &fb->fb.var;
0146     u32 val, cpl;
0147 
0148     /*
0149      * Program the CLCD controller registers and start the CLCD
0150      */
0151     val = ((var->xres / 16) - 1) << 2;
0152     val |= (var->hsync_len - 1) << 8;
0153     val |= (var->right_margin - 1) << 16;
0154     val |= (var->left_margin - 1) << 24;
0155     regs->tim0 = val;
0156 
0157     val = var->yres;
0158     if (fb->panel->cntl & CNTL_LCDDUAL)
0159         val /= 2;
0160     val -= 1;
0161     val |= (var->vsync_len - 1) << 10;
0162     val |= var->lower_margin << 16;
0163     val |= var->upper_margin << 24;
0164     regs->tim1 = val;
0165 
0166     val = fb->panel->tim2;
0167     val |= var->sync & FB_SYNC_HOR_HIGH_ACT  ? 0 : TIM2_IHS;
0168     val |= var->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
0169 
0170     cpl = var->xres_virtual;
0171     if (fb->panel->cntl & CNTL_LCDTFT)    /* TFT */
0172         /* / 1 */;
0173     else if (!var->grayscale)         /* STN color */
0174         cpl = cpl * 8 / 3;
0175     else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */
0176         cpl /= 8;
0177     else                      /* STN monochrome, 4bit */
0178         cpl /= 4;
0179 
0180     regs->tim2 = val | ((cpl - 1) << 16);
0181 
0182     regs->tim3 = fb->panel->tim3;
0183 
0184     val = fb->panel->cntl;
0185     if (var->grayscale)
0186         val |= CNTL_LCDBW;
0187 
0188     if (fb->panel->caps && fb->board->caps && var->bits_per_pixel >= 16) {
0189         /*
0190          * if board and panel supply capabilities, we can support
0191          * changing BGR/RGB depending on supplied parameters. Here
0192          * we switch to what the framebuffer is providing if need
0193          * be, so if the framebuffer is BGR but the display connection
0194          * is RGB (first case) we switch it around. Vice versa mutatis
0195          * mutandis if the framebuffer is RGB but the display connection
0196          * is BGR, we flip it around.
0197          */
0198         if (var->red.offset == 0)
0199             val &= ~CNTL_BGR;
0200         else
0201             val |= CNTL_BGR;
0202         if (fb->panel->bgr_connection)
0203             val ^= CNTL_BGR;
0204     }
0205 
0206     switch (var->bits_per_pixel) {
0207     case 1:
0208         val |= CNTL_LCDBPP1;
0209         break;
0210     case 2:
0211         val |= CNTL_LCDBPP2;
0212         break;
0213     case 4:
0214         val |= CNTL_LCDBPP4;
0215         break;
0216     case 8:
0217         val |= CNTL_LCDBPP8;
0218         break;
0219     case 16:
0220         /*
0221          * PL110 cannot choose between 5551 and 565 modes in its
0222          * control register.  It is possible to use 565 with
0223          * custom external wiring.
0224          */
0225         if (amba_part(fb->dev) == 0x110 ||
0226             var->green.length == 5)
0227             val |= CNTL_LCDBPP16;
0228         else if (var->green.length == 6)
0229             val |= CNTL_LCDBPP16_565;
0230         else
0231             val |= CNTL_LCDBPP16_444;
0232         break;
0233     case 32:
0234         val |= CNTL_LCDBPP24;
0235         break;
0236     }
0237 
0238     regs->cntl = val;
0239     regs->pixclock = var->pixclock;
0240 }
0241 
0242 static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
0243 {
0244     var->xres_virtual = var->xres = (var->xres + 15) & ~15;
0245     var->yres_virtual = var->yres = (var->yres + 1) & ~1;
0246 
0247 #define CHECK(e,l,h) (var->e < l || var->e > h)
0248     if (CHECK(right_margin, (5+1), 256) ||  /* back porch */
0249         CHECK(left_margin, (5+1), 256) ||   /* front porch */
0250         CHECK(hsync_len, (5+1), 256) ||
0251         var->xres > 4096 ||
0252         var->lower_margin > 255 ||      /* back porch */
0253         var->upper_margin > 255 ||      /* front porch */
0254         var->vsync_len > 32 ||
0255         var->yres > 1024)
0256         return -EINVAL;
0257 #undef CHECK
0258 
0259     /* single panel mode: PCD = max(PCD, 1) */
0260     /* dual panel mode: PCD = max(PCD, 5) */
0261 
0262     /*
0263      * You can't change the grayscale setting, and
0264      * we can only do non-interlaced video.
0265      */
0266     if (var->grayscale != fb->fb.var.grayscale ||
0267         (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
0268         return -EINVAL;
0269 
0270 #define CHECK(e) (var->e != fb->fb.var.e)
0271     if (fb->panel->fixedtimings &&
0272         (CHECK(xres)        ||
0273          CHECK(yres)        ||
0274          CHECK(bits_per_pixel)  ||
0275          CHECK(pixclock)        ||
0276          CHECK(left_margin)     ||
0277          CHECK(right_margin)    ||
0278          CHECK(upper_margin)    ||
0279          CHECK(lower_margin)    ||
0280          CHECK(hsync_len)       ||
0281          CHECK(vsync_len)       ||
0282          CHECK(sync)))
0283         return -EINVAL;
0284 #undef CHECK
0285 
0286     var->nonstd = 0;
0287     var->accel_flags = 0;
0288 
0289     return 0;
0290 }