Branch data Line data Source code
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 : : #define CLCD_PL110_IENB 0x00000018
25 : : #define CLCD_PL110_CNTL 0x0000001c
26 : : #define CLCD_PL110_STAT 0x00000020
27 : : #define CLCD_PL110_INTR 0x00000024
28 : : #define CLCD_PL110_UCUR 0x00000028
29 : : #define CLCD_PL110_LCUR 0x0000002C
30 : :
31 : : #define CLCD_PL111_CNTL 0x00000018
32 : : #define CLCD_PL111_IENB 0x0000001c
33 : : #define CLCD_PL111_RIS 0x00000020
34 : : #define CLCD_PL111_MIS 0x00000024
35 : : #define CLCD_PL111_ICR 0x00000028
36 : : #define CLCD_PL111_UCUR 0x0000002c
37 : : #define CLCD_PL111_LCUR 0x00000030
38 : :
39 : : #define CLCD_PALL 0x00000200
40 : : #define CLCD_PALETTE 0x00000200
41 : :
42 : : #define TIM2_CLKSEL (1 << 5)
43 : : #define TIM2_IVS (1 << 11)
44 : : #define TIM2_IHS (1 << 12)
45 : : #define TIM2_IPC (1 << 13)
46 : : #define TIM2_IOE (1 << 14)
47 : : #define TIM2_BCD (1 << 26)
48 : :
49 : : #define CNTL_LCDEN (1 << 0)
50 : : #define CNTL_LCDBPP1 (0 << 1)
51 : : #define CNTL_LCDBPP2 (1 << 1)
52 : : #define CNTL_LCDBPP4 (2 << 1)
53 : : #define CNTL_LCDBPP8 (3 << 1)
54 : : #define CNTL_LCDBPP16 (4 << 1)
55 : : #define CNTL_LCDBPP16_565 (6 << 1)
56 : : #define CNTL_LCDBPP16_444 (7 << 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 : :
70 : : enum {
71 : : /* individual formats */
72 : : CLCD_CAP_RGB444 = (1 << 0),
73 : : CLCD_CAP_RGB5551 = (1 << 1),
74 : : CLCD_CAP_RGB565 = (1 << 2),
75 : : CLCD_CAP_RGB888 = (1 << 3),
76 : : CLCD_CAP_BGR444 = (1 << 4),
77 : : CLCD_CAP_BGR5551 = (1 << 5),
78 : : CLCD_CAP_BGR565 = (1 << 6),
79 : : CLCD_CAP_BGR888 = (1 << 7),
80 : :
81 : : /* connection layouts */
82 : : CLCD_CAP_444 = CLCD_CAP_RGB444 | CLCD_CAP_BGR444,
83 : : CLCD_CAP_5551 = CLCD_CAP_RGB5551 | CLCD_CAP_BGR5551,
84 : : CLCD_CAP_565 = CLCD_CAP_RGB565 | CLCD_CAP_BGR565,
85 : : CLCD_CAP_888 = CLCD_CAP_RGB888 | CLCD_CAP_BGR888,
86 : :
87 : : /* red/blue ordering */
88 : : CLCD_CAP_RGB = CLCD_CAP_RGB444 | CLCD_CAP_RGB5551 |
89 : : CLCD_CAP_RGB565 | CLCD_CAP_RGB888,
90 : : CLCD_CAP_BGR = CLCD_CAP_BGR444 | CLCD_CAP_BGR5551 |
91 : : CLCD_CAP_BGR565 | CLCD_CAP_BGR888,
92 : :
93 : : CLCD_CAP_ALL = CLCD_CAP_BGR | CLCD_CAP_RGB,
94 : : };
95 : :
96 : : struct clcd_panel {
97 : : struct fb_videomode mode;
98 : : signed short width; /* width in mm */
99 : : signed short height; /* height in mm */
100 : : u32 tim2;
101 : : u32 tim3;
102 : : u32 cntl;
103 : : u32 caps;
104 : : unsigned int bpp:8,
105 : : fixedtimings:1,
106 : : grayscale:1;
107 : : unsigned int connector;
108 : : };
109 : :
110 : : struct clcd_regs {
111 : : u32 tim0;
112 : : u32 tim1;
113 : : u32 tim2;
114 : : u32 tim3;
115 : : u32 cntl;
116 : : unsigned long pixclock;
117 : : };
118 : :
119 : : struct clcd_fb;
120 : :
121 : : /*
122 : : * the board-type specific routines
123 : : */
124 : : struct clcd_board {
125 : : const char *name;
126 : :
127 : : /*
128 : : * Optional. Hardware capability flags.
129 : : */
130 : : u32 caps;
131 : :
132 : : /*
133 : : * Optional. Check whether the var structure is acceptable
134 : : * for this display.
135 : : */
136 : : int (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var);
137 : :
138 : : /*
139 : : * Compulsory. Decode fb->fb.var into regs->*. In the case of
140 : : * fixed timing, set regs->* to the register values required.
141 : : */
142 : : void (*decode)(struct clcd_fb *fb, struct clcd_regs *regs);
143 : :
144 : : /*
145 : : * Optional. Disable any extra display hardware.
146 : : */
147 : : void (*disable)(struct clcd_fb *);
148 : :
149 : : /*
150 : : * Optional. Enable any extra display hardware.
151 : : */
152 : : void (*enable)(struct clcd_fb *);
153 : :
154 : : /*
155 : : * Setup platform specific parts of CLCD driver
156 : : */
157 : : int (*setup)(struct clcd_fb *);
158 : :
159 : : /*
160 : : * mmap the framebuffer memory
161 : : */
162 : : int (*mmap)(struct clcd_fb *, struct vm_area_struct *);
163 : :
164 : : /*
165 : : * Remove platform specific parts of CLCD driver
166 : : */
167 : : void (*remove)(struct clcd_fb *);
168 : : };
169 : :
170 : : struct amba_device;
171 : : struct clk;
172 : :
173 : : /* this data structure describes each frame buffer device we find */
174 : : struct clcd_fb {
175 : : struct fb_info fb;
176 : : struct amba_device *dev;
177 : : struct clk *clk;
178 : : struct clcd_panel *panel;
179 : : struct clcd_board *board;
180 : : void *board_data;
181 : : void __iomem *regs;
182 : : u16 off_ienb;
183 : : u16 off_cntl;
184 : : u32 clcd_cntl;
185 : : u32 cmap[16];
186 : : bool clk_enabled;
187 : : };
188 : :
189 : 0 : static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
190 : : {
191 : : struct fb_var_screeninfo *var = &fb->fb.var;
192 : : u32 val, cpl;
193 : :
194 : : /*
195 : : * Program the CLCD controller registers and start the CLCD
196 : : */
197 : 0 : val = ((var->xres / 16) - 1) << 2;
198 : 0 : val |= (var->hsync_len - 1) << 8;
199 : 0 : val |= (var->right_margin - 1) << 16;
200 : 0 : val |= (var->left_margin - 1) << 24;
201 : 0 : regs->tim0 = val;
202 : :
203 : 0 : val = var->yres;
204 [ # # ]: 0 : if (fb->panel->cntl & CNTL_LCDDUAL)
205 : 0 : val /= 2;
206 : 0 : val -= 1;
207 : 0 : val |= (var->vsync_len - 1) << 10;
208 : 0 : val |= var->lower_margin << 16;
209 : 0 : val |= var->upper_margin << 24;
210 : 0 : regs->tim1 = val;
211 : :
212 : 0 : val = fb->panel->tim2;
213 [ # # ]: 0 : val |= var->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : TIM2_IHS;
214 [ # # ]: 0 : val |= var->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
215 : :
216 : 0 : cpl = var->xres_virtual;
217 [ # # ]: 0 : if (fb->panel->cntl & CNTL_LCDTFT) /* TFT */
218 : : /* / 1 */;
219 [ # # ]: 0 : else if (!var->grayscale) /* STN color */
220 : 0 : cpl = cpl * 8 / 3;
221 [ # # ]: 0 : else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */
222 : 0 : cpl /= 8;
223 : : else /* STN monochrome, 4bit */
224 : 0 : cpl /= 4;
225 : :
226 : 0 : regs->tim2 = val | ((cpl - 1) << 16);
227 : :
228 : 0 : regs->tim3 = fb->panel->tim3;
229 : :
230 : 0 : val = fb->panel->cntl;
231 [ # # ]: 0 : if (var->grayscale)
232 : 0 : val |= CNTL_LCDBW;
233 : :
234 [ # # ][ # # ]: 0 : if (fb->panel->caps && fb->board->caps &&
[ # # ]
235 : 0 : var->bits_per_pixel >= 16) {
236 : : /*
237 : : * if board and panel supply capabilities, we can support
238 : : * changing BGR/RGB depending on supplied parameters
239 : : */
240 [ # # ]: 0 : if (var->red.offset == 0)
241 : 0 : val &= ~CNTL_BGR;
242 : : else
243 : 0 : val |= CNTL_BGR;
244 : : }
245 : :
246 : : /* Reset the current colour depth */
247 : 0 : val &= ~CNTL_LCDBPP16_444;
248 : :
249 [ # # # # : 0 : switch (var->bits_per_pixel) {
# # ]
250 : : case 1:
251 : : val |= CNTL_LCDBPP1;
252 : : break;
253 : : case 2:
254 : 0 : val |= CNTL_LCDBPP2;
255 : 0 : break;
256 : : case 4:
257 : 0 : val |= CNTL_LCDBPP4;
258 : 0 : break;
259 : : case 8:
260 : 0 : val |= CNTL_LCDBPP8;
261 : 0 : break;
262 : : case 16:
263 : : /*
264 : : * PL110 cannot choose between 5551 and 565 modes in its
265 : : * control register. It is possible to use 565 with
266 : : * custom external wiring.
267 : : */
268 [ # # ][ # # ]: 0 : if (amba_part(fb->dev) == 0x110 ||
269 : 0 : var->green.length == 5)
270 : 0 : val |= CNTL_LCDBPP16 | CNTL_BGR;
271 [ # # ]: 0 : else if (var->green.length == 6)
272 : 0 : val |= CNTL_LCDBPP16_565 | CNTL_BGR;
273 : : else
274 : 0 : val |= CNTL_LCDBPP16_444 | CNTL_BGR;
275 : : break;
276 : : case 32:
277 : : val |= CNTL_LCDBPP24;
278 : 0 : val &= ~CNTL_BGR;
279 : 0 : break;
280 : : }
281 : :
282 : 0 : regs->cntl = val;
283 : 0 : regs->pixclock = var->pixclock;
284 : 0 : }
285 : :
286 : 0 : static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
287 : : {
288 : 0 : var->xres_virtual = var->xres = (var->xres + 15) & ~15;
289 : 0 : var->yres_virtual = var->yres = (var->yres + 1) & ~1;
290 : :
291 : : #define CHECK(e,l,h) (var->e < l || var->e > h)
292 [ # # ][ # # ]: 0 : if (CHECK(right_margin, (5+1), 256) || /* back porch */
293 [ # # ]: 0 : CHECK(left_margin, (5+1), 256) || /* front porch */
294 [ # # ]: 0 : CHECK(hsync_len, (5+1), 256) ||
295 [ # # ]: 0 : var->xres > 4096 ||
296 [ # # ]: 0 : var->lower_margin > 255 || /* back porch */
297 [ # # ]: 0 : var->upper_margin > 255 || /* front porch */
298 [ # # ]: 0 : var->vsync_len > 32 ||
299 : : var->yres > 1024)
300 : : return -EINVAL;
301 : : #undef CHECK
302 : :
303 : : /* single panel mode: PCD = max(PCD, 1) */
304 : : /* dual panel mode: PCD = max(PCD, 5) */
305 : :
306 : : /*
307 : : * You can't change the grayscale setting, and
308 : : * we can only do non-interlaced video.
309 : : */
310 [ # # ][ # # ]: 0 : if (var->grayscale != fb->fb.var.grayscale ||
311 : 0 : (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
312 : : return -EINVAL;
313 : :
314 : : #define CHECK(e) (var->e != fb->fb.var.e)
315 [ # # ][ # # ]: 0 : if (fb->panel->fixedtimings &&
316 [ # # ]: 0 : (CHECK(xres) ||
317 [ # # ]: 0 : CHECK(yres) ||
318 [ # # ]: 0 : CHECK(bits_per_pixel) ||
319 [ # # ]: 0 : CHECK(pixclock) ||
320 [ # # ]: 0 : CHECK(left_margin) ||
321 [ # # ]: 0 : CHECK(right_margin) ||
322 [ # # ]: 0 : CHECK(upper_margin) ||
323 [ # # ]: 0 : CHECK(lower_margin) ||
324 [ # # ]: 0 : CHECK(hsync_len) ||
325 [ # # ]: 0 : CHECK(vsync_len) ||
326 : 0 : CHECK(sync)))
327 : : return -EINVAL;
328 : : #undef CHECK
329 : :
330 : 0 : var->nonstd = 0;
331 : 0 : var->accel_flags = 0;
332 : :
333 : 0 : return 0;
334 : : }
|