diff options
author | Arnaud Patard (Rtp <arnaud.patard@rtp-net.org> | 2006-12-08 05:40:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:29:05 -0500 |
commit | 357b819dda03e642f9c2d737596ad6cdc0022c00 (patch) | |
tree | 0d4639e901e07bc04ee9800fd6d2a636b0f02429 | |
parent | c25623f5540694ba70af272170d67f1411be97b1 (diff) |
[PATCH] s3c2410fb: Add support for STN displays
This patch adds support for stn displays on the s3c2410 arm SoC.
The LCD type is choosen by a new field in the s3c2410fb_mach_info structure
and its value is the value of the PNRMODE bits. This worth to be noted as
a value of 0 means that you configure a 4 bit dual scan stn display.
Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Ben Dooks <ben-linux@fluff.org>
Acked-by: James Simmons <jsimmons@infradead.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/video/s3c2410fb.c | 213 | ||||
-rw-r--r-- | include/asm-arm/arch-s3c2410/fb.h | 3 |
2 files changed, 173 insertions, 43 deletions
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 59407343cc73..ccef56d0c157 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c | |||
@@ -131,7 +131,7 @@ static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi) | |||
131 | saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8; | 131 | saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8; |
132 | saddr2>>= 1; | 132 | saddr2>>= 1; |
133 | 133 | ||
134 | saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(var->xres); | 134 | saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff); |
135 | 135 | ||
136 | dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); | 136 | dprintk("LCDSADDR1 = 0x%08lx\n", saddr1); |
137 | dprintk("LCDSADDR2 = 0x%08lx\n", saddr2); | 137 | dprintk("LCDSADDR2 = 0x%08lx\n", saddr2); |
@@ -199,28 +199,86 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var, | |||
199 | var->bits_per_pixel = fbi->mach_info->bpp.min; | 199 | var->bits_per_pixel = fbi->mach_info->bpp.min; |
200 | 200 | ||
201 | /* set r/g/b positions */ | 201 | /* set r/g/b positions */ |
202 | switch (var->bits_per_pixel) { | ||
203 | case 1: | ||
204 | case 2: | ||
205 | case 4: | ||
206 | var->red.offset = 0; | ||
207 | var->red.length = var->bits_per_pixel; | ||
208 | var->green = var->red; | ||
209 | var->blue = var->red; | ||
210 | var->transp.offset = 0; | ||
211 | var->transp.length = 0; | ||
212 | break; | ||
213 | case 8: | ||
214 | if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) { | ||
215 | /* 8 bpp 332 */ | ||
216 | var->red.length = 3; | ||
217 | var->red.offset = 5; | ||
218 | var->green.length = 3; | ||
219 | var->green.offset = 2; | ||
220 | var->blue.length = 2; | ||
221 | var->blue.offset = 0; | ||
222 | var->transp.length = 0; | ||
223 | } else { | ||
224 | var->red.offset = 0; | ||
225 | var->red.length = var->bits_per_pixel; | ||
226 | var->green = var->red; | ||
227 | var->blue = var->red; | ||
228 | var->transp.offset = 0; | ||
229 | var->transp.length = 0; | ||
230 | } | ||
231 | break; | ||
232 | case 12: | ||
233 | /* 12 bpp 444 */ | ||
234 | var->red.length = 4; | ||
235 | var->red.offset = 8; | ||
236 | var->green.length = 4; | ||
237 | var->green.offset = 4; | ||
238 | var->blue.length = 4; | ||
239 | var->blue.offset = 0; | ||
240 | var->transp.length = 0; | ||
241 | break; | ||
242 | |||
243 | default: | ||
244 | case 16: | ||
245 | if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) { | ||
246 | /* 16 bpp, 565 format */ | ||
247 | var->red.offset = 11; | ||
248 | var->green.offset = 5; | ||
249 | var->blue.offset = 0; | ||
250 | var->red.length = 5; | ||
251 | var->green.length = 6; | ||
252 | var->blue.length = 5; | ||
253 | var->transp.length = 0; | ||
254 | } else { | ||
255 | /* 16 bpp, 5551 format */ | ||
256 | var->red.offset = 11; | ||
257 | var->green.offset = 6; | ||
258 | var->blue.offset = 1; | ||
259 | var->red.length = 5; | ||
260 | var->green.length = 5; | ||
261 | var->blue.length = 5; | ||
262 | var->transp.length = 0; | ||
263 | } | ||
264 | break; | ||
265 | case 24: | ||
266 | /* 24 bpp 888 */ | ||
267 | var->red.length = 8; | ||
268 | var->red.offset = 16; | ||
269 | var->green.length = 8; | ||
270 | var->green.offset = 8; | ||
271 | var->blue.length = 8; | ||
272 | var->blue.offset = 0; | ||
273 | var->transp.length = 0; | ||
274 | break; | ||
202 | 275 | ||
203 | if (var->bits_per_pixel == 16) { | ||
204 | var->red.offset = 11; | ||
205 | var->green.offset = 5; | ||
206 | var->blue.offset = 0; | ||
207 | var->red.length = 5; | ||
208 | var->green.length = 6; | ||
209 | var->blue.length = 5; | ||
210 | var->transp.length = 0; | ||
211 | } else { | ||
212 | var->red.length = var->bits_per_pixel; | ||
213 | var->red.offset = 0; | ||
214 | var->green.length = var->bits_per_pixel; | ||
215 | var->green.offset = 0; | ||
216 | var->blue.length = var->bits_per_pixel; | ||
217 | var->blue.offset = 0; | ||
218 | var->transp.length = 0; | ||
219 | } | ||
220 | 276 | ||
277 | } | ||
221 | return 0; | 278 | return 0; |
222 | } | 279 | } |
223 | 280 | ||
281 | |||
224 | /* s3c2410fb_activate_var | 282 | /* s3c2410fb_activate_var |
225 | * | 283 | * |
226 | * activate (set) the controller from the given framebuffer | 284 | * activate (set) the controller from the given framebuffer |
@@ -230,29 +288,61 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var, | |||
230 | static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi, | 288 | static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi, |
231 | struct fb_var_screeninfo *var) | 289 | struct fb_var_screeninfo *var) |
232 | { | 290 | { |
291 | int hs; | ||
292 | |||
233 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK; | 293 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK; |
294 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT; | ||
234 | 295 | ||
235 | dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); | 296 | dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); |
236 | dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); | 297 | dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); |
237 | dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); | 298 | dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); |
238 | 299 | ||
239 | switch (var->bits_per_pixel) { | 300 | fbi->regs.lcdcon1 |= fbi->mach_info->type; |
240 | case 1: | 301 | |
241 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; | 302 | if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) |
242 | break; | 303 | switch (var->bits_per_pixel) { |
243 | case 2: | 304 | case 1: |
244 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; | 305 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; |
245 | break; | 306 | break; |
246 | case 4: | 307 | case 2: |
247 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; | 308 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP; |
248 | break; | 309 | break; |
249 | case 8: | 310 | case 4: |
250 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; | 311 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP; |
251 | break; | 312 | break; |
252 | case 16: | 313 | case 8: |
253 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; | 314 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP; |
254 | break; | 315 | break; |
255 | } | 316 | case 16: |
317 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP; | ||
318 | break; | ||
319 | |||
320 | default: | ||
321 | /* invalid pixel depth */ | ||
322 | dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel); | ||
323 | } | ||
324 | else | ||
325 | switch (var->bits_per_pixel) { | ||
326 | case 1: | ||
327 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP; | ||
328 | break; | ||
329 | case 2: | ||
330 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY; | ||
331 | break; | ||
332 | case 4: | ||
333 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY; | ||
334 | break; | ||
335 | case 8: | ||
336 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP; | ||
337 | break; | ||
338 | case 12: | ||
339 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP; | ||
340 | break; | ||
341 | |||
342 | default: | ||
343 | /* invalid pixel depth */ | ||
344 | dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel); | ||
345 | } | ||
256 | 346 | ||
257 | /* check to see if we need to update sync/borders */ | 347 | /* check to see if we need to update sync/borders */ |
258 | 348 | ||
@@ -283,15 +373,44 @@ static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi, | |||
283 | fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff); | 373 | fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff); |
284 | fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1); | 374 | fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1); |
285 | 375 | ||
376 | switch(fbi->mach_info->type) { | ||
377 | case S3C2410_LCDCON1_DSCAN4: | ||
378 | case S3C2410_LCDCON1_STN8: | ||
379 | hs = var->xres / 8; | ||
380 | break; | ||
381 | case S3C2410_LCDCON1_STN4: | ||
382 | hs = var->xres / 4; | ||
383 | break; | ||
384 | default: | ||
385 | case S3C2410_LCDCON1_TFT: | ||
386 | hs = var->xres; | ||
387 | break; | ||
388 | |||
389 | } | ||
390 | |||
391 | /* Special cases : STN color displays */ | ||
392 | if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \ | ||
393 | || ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) { | ||
394 | hs = hs * 3; | ||
395 | } | ||
396 | |||
397 | |||
286 | fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff); | 398 | fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff); |
287 | fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(var->xres - 1); | 399 | fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1); |
288 | 400 | ||
289 | if (var->pixclock > 0) { | 401 | if (var->pixclock > 0) { |
290 | int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock); | 402 | int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock); |
291 | 403 | ||
292 | clkdiv = (clkdiv / 2) -1; | 404 | if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) { |
293 | if (clkdiv < 0) | 405 | clkdiv = (clkdiv / 2) -1; |
294 | clkdiv = 0; | 406 | if (clkdiv < 0) |
407 | clkdiv = 0; | ||
408 | } | ||
409 | else { | ||
410 | clkdiv = (clkdiv / 2); | ||
411 | if (clkdiv < 2) | ||
412 | clkdiv = 2; | ||
413 | } | ||
295 | 414 | ||
296 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff); | 415 | fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff); |
297 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); | 416 | fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); |
@@ -329,10 +448,18 @@ static int s3c2410fb_set_par(struct fb_info *info) | |||
329 | struct s3c2410fb_info *fbi = info->par; | 448 | struct s3c2410fb_info *fbi = info->par; |
330 | struct fb_var_screeninfo *var = &info->var; | 449 | struct fb_var_screeninfo *var = &info->var; |
331 | 450 | ||
332 | if (var->bits_per_pixel == 16) | 451 | switch (var->bits_per_pixel) |
333 | fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR; | 452 | { |
334 | else | 453 | case 16: |
335 | fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 454 | fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR; |
455 | break; | ||
456 | case 1: | ||
457 | fbi->fb->fix.visual = FB_VISUAL_MONO01; | ||
458 | break; | ||
459 | default: | ||
460 | fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
461 | break; | ||
462 | } | ||
336 | 463 | ||
337 | fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8; | 464 | fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8; |
338 | 465 | ||
diff --git a/include/asm-arm/arch-s3c2410/fb.h b/include/asm-arm/arch-s3c2410/fb.h index 90894214cace..93a58e7862b0 100644 --- a/include/asm-arm/arch-s3c2410/fb.h +++ b/include/asm-arm/arch-s3c2410/fb.h | |||
@@ -31,6 +31,9 @@ struct s3c2410fb_hw { | |||
31 | struct s3c2410fb_mach_info { | 31 | struct s3c2410fb_mach_info { |
32 | unsigned char fixed_syncs; /* do not update sync/border */ | 32 | unsigned char fixed_syncs; /* do not update sync/border */ |
33 | 33 | ||
34 | /* LCD types */ | ||
35 | int type; | ||
36 | |||
34 | /* Screen size */ | 37 | /* Screen size */ |
35 | int width; | 38 | int width; |
36 | int height; | 39 | int height; |