0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/fb.h>
0013 #include <linux/amba/clcd-regs.h>
0014
0015 enum {
0016
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
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
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;
0046 signed short height;
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
0058
0059
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
0077
0078 struct clcd_board {
0079 const char *name;
0080
0081
0082
0083
0084 u32 caps;
0085
0086
0087
0088
0089
0090 int (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var);
0091
0092
0093
0094
0095
0096 void (*decode)(struct clcd_fb *fb, struct clcd_regs *regs);
0097
0098
0099
0100
0101 void (*disable)(struct clcd_fb *);
0102
0103
0104
0105
0106 void (*enable)(struct clcd_fb *);
0107
0108
0109
0110
0111 int (*setup)(struct clcd_fb *);
0112
0113
0114
0115
0116 int (*mmap)(struct clcd_fb *, struct vm_area_struct *);
0117
0118
0119
0120
0121 void (*remove)(struct clcd_fb *);
0122 };
0123
0124 struct amba_device;
0125 struct clk;
0126
0127
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
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)
0172 ;
0173 else if (!var->grayscale)
0174 cpl = cpl * 8 / 3;
0175 else if (fb->panel->cntl & CNTL_LCDMONO8)
0176 cpl /= 8;
0177 else
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
0191
0192
0193
0194
0195
0196
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
0222
0223
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) ||
0249 CHECK(left_margin, (5+1), 256) ||
0250 CHECK(hsync_len, (5+1), 256) ||
0251 var->xres > 4096 ||
0252 var->lower_margin > 255 ||
0253 var->upper_margin > 255 ||
0254 var->vsync_len > 32 ||
0255 var->yres > 1024)
0256 return -EINVAL;
0257 #undef CHECK
0258
0259
0260
0261
0262
0263
0264
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 }