aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/s3c2410fb.c234
1 files changed, 136 insertions, 98 deletions
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index e52ec2283161..04e9d7a482fa 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -197,6 +197,14 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
197 return -EINVAL; 197 return -EINVAL;
198 } 198 }
199 199
200 /* it is always the size as the display */
201 var->xres_virtual = display->xres;
202 var->yres_virtual = display->yres;
203
204 /* copy lcd settings */
205 var->left_margin = display->left_margin;
206 var->right_margin = display->right_margin;
207
200 var->transp.offset = 0; 208 var->transp.offset = 0;
201 var->transp.length = 0; 209 var->transp.length = 0;
202 /* set r/g/b positions */ 210 /* set r/g/b positions */
@@ -270,124 +278,151 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
270 return 0; 278 return 0;
271} 279}
272 280
273/* s3c2410fb_activate_var 281/* s3c2410fb_calculate_stn_lcd_regs
274 * 282 *
275 * activate (set) the controller from the given framebuffer 283 * calculate register values from var settings
276 * information
277 */ 284 */
278static void s3c2410fb_activate_var(struct fb_info *info, 285static void s3c2410fb_calculate_stn_lcd_regs(const struct fb_info *info,
279 struct fb_var_screeninfo *var) 286 struct s3c2410fb_hw *regs)
280{ 287{
281 struct s3c2410fb_info *fbi = info->par; 288 const struct s3c2410fb_info *fbi = info->par;
282 struct s3c2410fb_mach_info *mach_info = fbi->mach_info; 289 const struct fb_var_screeninfo *var = &info->var;
283 struct s3c2410fb_display *display = mach_info->displays + 290 int type = regs->lcdcon1 & ~S3C2410_LCDCON1_TFT;
284 fbi->current_display; 291 int hs = var->xres >> 2;
285 int hs; 292 unsigned wdly = (var->left_margin >> 4) - 1;
286
287 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
288 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT;
289 293
290 dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres); 294 dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres);
291 dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); 295 dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
292 dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); 296 dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);
293 297
294 fbi->regs.lcdcon1 |= display->type; 298 if (type != S3C2410_LCDCON1_STN4)
295 299 hs >>= 1;
296 if (display->type == S3C2410_LCDCON1_TFT)
297 switch (var->bits_per_pixel) {
298 case 1:
299 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
300 break;
301 case 2:
302 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
303 break;
304 case 4:
305 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
306 break;
307 case 8:
308 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
309 break;
310 case 16:
311 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
312 break;
313 300
314 default: 301 regs->lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
315 /* invalid pixel depth */
316 dev_err(fbi->dev, "invalid bpp %d\n",
317 var->bits_per_pixel);
318 }
319 else
320 switch (var->bits_per_pixel) {
321 case 1:
322 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
323 break;
324 case 2:
325 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
326 break;
327 case 4:
328 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
329 break;
330 case 8:
331 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
332 break;
333 case 12:
334 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
335 break;
336 302
337 default: 303 switch (var->bits_per_pixel) {
338 /* invalid pixel depth */ 304 case 1:
339 dev_err(fbi->dev, "invalid bpp %d\n", 305 regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
340 var->bits_per_pixel); 306 break;
341 } 307 case 2:
308 regs->lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
309 break;
310 case 4:
311 regs->lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
312 break;
313 case 8:
314 regs->lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
315 hs *= 3;
316 break;
317 case 12:
318 regs->lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
319 hs *= 3;
320 break;
342 321
343 /* check to see if we need to update sync/borders */ 322 default:
323 /* invalid pixel depth */
324 dev_err(fbi->dev, "invalid bpp %d\n",
325 var->bits_per_pixel);
326 }
327 /* update X/Y info */
328 dprintk("setting vert: up=%d, low=%d, sync=%d\n",
329 var->upper_margin, var->lower_margin, var->vsync_len);
344 330
345 if (!mach_info->fixed_syncs) { 331 dprintk("setting horz: lft=%d, rt=%d, sync=%d\n",
346 dprintk("setting vert: up=%d, low=%d, sync=%d\n", 332 var->left_margin, var->right_margin, var->hsync_len);
347 var->upper_margin, var->lower_margin, var->vsync_len);
348 333
349 dprintk("setting horz: lft=%d, rt=%d, sync=%d\n", 334 regs->lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff);
350 var->left_margin, var->right_margin, var->hsync_len); 335 regs->lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1);
351 336
352 fbi->regs.lcdcon2 = 337 if (wdly > 3)
353 S3C2410_LCDCON2_VBPD(var->upper_margin - 1) | 338 wdly = 3;
354 S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
355 S3C2410_LCDCON2_VSPW(var->vsync_len - 1);
356 339
357 fbi->regs.lcdcon3 = 340 regs->lcdcon3 = S3C2410_LCDCON3_WDLY(wdly) |
358 S3C2410_LCDCON3_HBPD(var->right_margin - 1) | 341 S3C2410_LCDCON3_LINEBLANK(var->right_margin / 8) |
359 S3C2410_LCDCON3_HFPD(var->left_margin - 1); 342 S3C2410_LCDCON3_HOZVAL(hs - 1);
343}
360 344
361 fbi->regs.lcdcon4 &= ~S3C2410_LCDCON4_HSPW(0xff); 345/* s3c2410fb_calculate_tft_lcd_regs
362 fbi->regs.lcdcon4 |= S3C2410_LCDCON4_HSPW(var->hsync_len - 1); 346 *
363 } 347 * calculate register values from var settings
348 */
349static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info,
350 struct s3c2410fb_hw *regs)
351{
352 const struct s3c2410fb_info *fbi = info->par;
353 const struct fb_var_screeninfo *var = &info->var;
364 354
365 /* update X/Y info */ 355 dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres);
356 dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
357 dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);
366 358
367 fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff); 359 regs->lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
368 fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1);
369 360
370 switch (display->type) { 361 switch (var->bits_per_pixel) {
371 case S3C2410_LCDCON1_DSCAN4: 362 case 1:
372 case S3C2410_LCDCON1_STN8: 363 regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
373 hs = var->xres / 8; 364 break;
365 case 2:
366 regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
374 break; 367 break;
375 case S3C2410_LCDCON1_STN4: 368 case 4:
376 hs = var->xres / 4; 369 regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
377 break; 370 break;
378 default: 371 case 8:
379 case S3C2410_LCDCON1_TFT: 372 regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
380 hs = var->xres; 373 break;
374 case 16:
375 regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
381 break; 376 break;
377
378 default:
379 /* invalid pixel depth */
380 dev_err(fbi->dev, "invalid bpp %d\n",
381 var->bits_per_pixel);
382 } 382 }
383 /* update X/Y info */
384 dprintk("setting vert: up=%d, low=%d, sync=%d\n",
385 var->upper_margin, var->lower_margin, var->vsync_len);
383 386
384 /* Special cases : STN color displays */ 387 dprintk("setting horz: lft=%d, rt=%d, sync=%d\n",
385 if (((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) || 388 var->left_margin, var->right_margin, var->hsync_len);
386 ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP))
387 hs = hs * 3;
388 389
389 fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff); 390 regs->lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff);
390 fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1); 391 regs->lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1);
392
393 regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |
394 S3C2410_LCDCON3_HFPD(var->left_margin - 1) |
395 S3C2410_LCDCON3_HOZVAL(var->xres - 1);
396}
397
398/* s3c2410fb_activate_var
399 *
400 * activate (set) the controller from the given framebuffer
401 * information
402 */
403static void s3c2410fb_activate_var(struct fb_info *info)
404{
405 struct s3c2410fb_info *fbi = info->par;
406 struct fb_var_screeninfo *var = &info->var;
407 struct s3c2410fb_mach_info *mach_info = fbi->mach_info;
408 struct s3c2410fb_display *display = mach_info->displays +
409 fbi->current_display;
410
411 /* set display type */
412 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT;
413 fbi->regs.lcdcon1 |= display->type;
414
415 /* check to see if we need to update sync/borders */
416
417 if (!mach_info->fixed_syncs) {
418 fbi->regs.lcdcon2 =
419 S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |
420 S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
421 S3C2410_LCDCON2_VSPW(var->vsync_len - 1);
422
423 fbi->regs.lcdcon4 &= ~S3C2410_LCDCON4_HSPW(0xff);
424 fbi->regs.lcdcon4 |= S3C2410_LCDCON4_HSPW(var->hsync_len - 1);
425 }
391 426
392 if (var->pixclock > 0) { 427 if (var->pixclock > 0) {
393 int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock); 428 int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock);
@@ -406,6 +441,11 @@ static void s3c2410fb_activate_var(struct fb_info *info,
406 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv); 441 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
407 } 442 }
408 443
444 if (display->type == S3C2410_LCDCON1_TFT)
445 s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);
446 else
447 s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);
448
409 /* write new registers */ 449 /* write new registers */
410 450
411 dprintk("new register set:\n"); 451 dprintk("new register set:\n");
@@ -452,7 +492,7 @@ static int s3c2410fb_set_par(struct fb_info *info)
452 492
453 /* activate this new configuration */ 493 /* activate this new configuration */
454 494
455 s3c2410fb_activate_var(info, var); 495 s3c2410fb_activate_var(info);
456 return 0; 496 return 0;
457} 497}
458 498
@@ -848,6 +888,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
848 fbinfo->var.yres = display->yres; 888 fbinfo->var.yres = display->yres;
849 fbinfo->var.yres_virtual = display->yres; 889 fbinfo->var.yres_virtual = display->yres;
850 fbinfo->var.bits_per_pixel = display->bpp; 890 fbinfo->var.bits_per_pixel = display->bpp;
891 fbinfo->var.left_margin = display->left_margin;
892 fbinfo->var.right_margin = display->right_margin;
851 893
852 fbinfo->var.upper_margin = 894 fbinfo->var.upper_margin =
853 S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1; 895 S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1;
@@ -856,10 +898,6 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
856 fbinfo->var.vsync_len = 898 fbinfo->var.vsync_len =
857 S3C2410_LCDCON2_GET_VSPW(mregs->lcdcon2) + 1; 899 S3C2410_LCDCON2_GET_VSPW(mregs->lcdcon2) + 1;
858 900
859 fbinfo->var.left_margin =
860 S3C2410_LCDCON3_GET_HFPD(mregs->lcdcon3) + 1;
861 fbinfo->var.right_margin =
862 S3C2410_LCDCON3_GET_HBPD(mregs->lcdcon3) + 1;
863 fbinfo->var.hsync_len = 901 fbinfo->var.hsync_len =
864 S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1; 902 S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1;
865 903