diff options
-rw-r--r-- | drivers/video/s3c2410fb.c | 234 |
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 | */ |
278 | static void s3c2410fb_activate_var(struct fb_info *info, | 285 | static 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 | */ | ||
349 | static 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 | */ | ||
403 | static 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 | ||