Skip to content

Commit

Permalink
[PATCH] s3c2410fb: Add support for STN displays
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Arnaud Patard (Rtp authored and Linus Torvalds committed Dec 8, 2006
1 parent c25623f commit 357b819
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 43 deletions.
213 changes: 170 additions & 43 deletions drivers/video/s3c2410fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi)
saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8;
saddr2>>= 1;

saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(var->xres);
saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff);

dprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
dprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
Expand Down Expand Up @@ -199,28 +199,86 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
var->bits_per_pixel = fbi->mach_info->bpp.min;

/* set r/g/b positions */
switch (var->bits_per_pixel) {
case 1:
case 2:
case 4:
var->red.offset = 0;
var->red.length = var->bits_per_pixel;
var->green = var->red;
var->blue = var->red;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 8:
if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) {
/* 8 bpp 332 */
var->red.length = 3;
var->red.offset = 5;
var->green.length = 3;
var->green.offset = 2;
var->blue.length = 2;
var->blue.offset = 0;
var->transp.length = 0;
} else {
var->red.offset = 0;
var->red.length = var->bits_per_pixel;
var->green = var->red;
var->blue = var->red;
var->transp.offset = 0;
var->transp.length = 0;
}
break;
case 12:
/* 12 bpp 444 */
var->red.length = 4;
var->red.offset = 8;
var->green.length = 4;
var->green.offset = 4;
var->blue.length = 4;
var->blue.offset = 0;
var->transp.length = 0;
break;

default:
case 16:
if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) {
/* 16 bpp, 565 format */
var->red.offset = 11;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
var->transp.length = 0;
} else {
/* 16 bpp, 5551 format */
var->red.offset = 11;
var->green.offset = 6;
var->blue.offset = 1;
var->red.length = 5;
var->green.length = 5;
var->blue.length = 5;
var->transp.length = 0;
}
break;
case 24:
/* 24 bpp 888 */
var->red.length = 8;
var->red.offset = 16;
var->green.length = 8;
var->green.offset = 8;
var->blue.length = 8;
var->blue.offset = 0;
var->transp.length = 0;
break;

if (var->bits_per_pixel == 16) {
var->red.offset = 11;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
var->transp.length = 0;
} else {
var->red.length = var->bits_per_pixel;
var->red.offset = 0;
var->green.length = var->bits_per_pixel;
var->green.offset = 0;
var->blue.length = var->bits_per_pixel;
var->blue.offset = 0;
var->transp.length = 0;
}

}
return 0;
}


/* s3c2410fb_activate_var
*
* activate (set) the controller from the given framebuffer
Expand All @@ -230,29 +288,61 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
struct fb_var_screeninfo *var)
{
int hs;

fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT;

dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres);
dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);

switch (var->bits_per_pixel) {
case 1:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
break;
case 2:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
break;
case 4:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
break;
case 8:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
break;
case 16:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
break;
}
fbi->regs.lcdcon1 |= fbi->mach_info->type;

if (fbi->mach_info->type == S3C2410_LCDCON1_TFT)
switch (var->bits_per_pixel) {
case 1:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
break;
case 2:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
break;
case 4:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
break;
case 8:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
break;
case 16:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
break;

default:
/* invalid pixel depth */
dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
}
else
switch (var->bits_per_pixel) {
case 1:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
break;
case 2:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
break;
case 4:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
break;
case 8:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
break;
case 12:
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
break;

default:
/* invalid pixel depth */
dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
}

/* check to see if we need to update sync/borders */

Expand Down Expand Up @@ -283,15 +373,44 @@ static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff);
fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1);

switch(fbi->mach_info->type) {
case S3C2410_LCDCON1_DSCAN4:
case S3C2410_LCDCON1_STN8:
hs = var->xres / 8;
break;
case S3C2410_LCDCON1_STN4:
hs = var->xres / 4;
break;
default:
case S3C2410_LCDCON1_TFT:
hs = var->xres;
break;

}

/* Special cases : STN color displays */
if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \
|| ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) {
hs = hs * 3;
}


fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff);
fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(var->xres - 1);
fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1);

if (var->pixclock > 0) {
int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock);

clkdiv = (clkdiv / 2) -1;
if (clkdiv < 0)
clkdiv = 0;
if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) {
clkdiv = (clkdiv / 2) -1;
if (clkdiv < 0)
clkdiv = 0;
}
else {
clkdiv = (clkdiv / 2);
if (clkdiv < 2)
clkdiv = 2;
}

fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff);
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
Expand Down Expand Up @@ -329,10 +448,18 @@ static int s3c2410fb_set_par(struct fb_info *info)
struct s3c2410fb_info *fbi = info->par;
struct fb_var_screeninfo *var = &info->var;

if (var->bits_per_pixel == 16)
fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
else
fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
switch (var->bits_per_pixel)
{
case 16:
fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
break;
case 1:
fbi->fb->fix.visual = FB_VISUAL_MONO01;
break;
default:
fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
break;
}

fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8;

Expand Down
3 changes: 3 additions & 0 deletions include/asm-arm/arch-s3c2410/fb.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ struct s3c2410fb_hw {
struct s3c2410fb_mach_info {
unsigned char fixed_syncs; /* do not update sync/border */

/* LCD types */
int type;

/* Screen size */
int width;
int height;
Expand Down

0 comments on commit 357b819

Please sign in to comment.