aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2007-10-16 04:28:56 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:16 -0400
commit09fe75f6f934597f765748342ca6fb378ee7ecdb (patch)
tree55a3ab7bf52400be136ec533cd5ebda4336fcd07 /drivers/video
parent110c1fa75463c4f327e9fc491e9a27e938800d96 (diff)
s3c2410fb: multi-display support
This patch adds a new structure to describe and handle more than one panel (display mode) for the s3c2410 framebuffer. This structure is added after the pxafb driver. Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Signed-off-by: Antonino Daplas <adaplas@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/s3c2410fb.c83
-rw-r--r--drivers/video/s3c2410fb.h2
2 files changed, 51 insertions, 34 deletions
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index f7a026fa5079..e52ec2283161 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -174,27 +174,28 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
174 struct fb_info *info) 174 struct fb_info *info)
175{ 175{
176 struct s3c2410fb_info *fbi = info->par; 176 struct s3c2410fb_info *fbi = info->par;
177 struct s3c2410fb_mach_info *mach_info = fbi->mach_info;
178 struct s3c2410fb_display *display = NULL;
179 unsigned i;
177 180
178 dprintk("check_var(var=%p, info=%p)\n", var, info); 181 dprintk("check_var(var=%p, info=%p)\n", var, info);
179 182
180 /* validate x/y resolution */ 183 /* validate x/y resolution */
181 184
182 if (var->yres > fbi->mach_info->yres.max) 185 for (i = 0; i < mach_info->num_displays; i++)
183 var->yres = fbi->mach_info->yres.max; 186 if (var->yres == mach_info->displays[i].yres &&
184 else if (var->yres < fbi->mach_info->yres.min) 187 var->xres == mach_info->displays[i].xres &&
185 var->yres = fbi->mach_info->yres.min; 188 var->bits_per_pixel == mach_info->displays[i].bpp) {
186 189 display = mach_info->displays + i;
187 if (var->xres > fbi->mach_info->xres.max) 190 fbi->current_display = i;
188 var->yres = fbi->mach_info->xres.max; 191 break;
189 else if (var->xres < fbi->mach_info->xres.min) 192 }
190 var->xres = fbi->mach_info->xres.min;
191
192 /* validate bpp */
193 193
194 if (var->bits_per_pixel > fbi->mach_info->bpp.max) 194 if (!display) {
195 var->bits_per_pixel = fbi->mach_info->bpp.max; 195 dprintk("wrong resolution or depth %dx%d at %d bpp\n",
196 else if (var->bits_per_pixel < fbi->mach_info->bpp.min) 196 var->xres, var->yres, var->bits_per_pixel);
197 var->bits_per_pixel = fbi->mach_info->bpp.min; 197 return -EINVAL;
198 }
198 199
199 var->transp.offset = 0; 200 var->transp.offset = 0;
200 var->transp.length = 0; 201 var->transp.length = 0;
@@ -209,7 +210,7 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
209 var->blue = var->red; 210 var->blue = var->red;
210 break; 211 break;
211 case 8: 212 case 8:
212 if (fbi->mach_info->type != S3C2410_LCDCON1_TFT) { 213 if (display->type != S3C2410_LCDCON1_TFT) {
213 /* 8 bpp 332 */ 214 /* 8 bpp 332 */
214 var->red.length = 3; 215 var->red.length = 3;
215 var->red.offset = 5; 216 var->red.offset = 5;
@@ -236,7 +237,7 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
236 237
237 default: 238 default:
238 case 16: 239 case 16:
239 if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565) { 240 if (display->regs.lcdcon5 & S3C2410_LCDCON5_FRM565) {
240 /* 16 bpp, 565 format */ 241 /* 16 bpp, 565 format */
241 var->red.offset = 11; 242 var->red.offset = 11;
242 var->green.offset = 5; 243 var->green.offset = 5;
@@ -278,6 +279,9 @@ static void s3c2410fb_activate_var(struct fb_info *info,
278 struct fb_var_screeninfo *var) 279 struct fb_var_screeninfo *var)
279{ 280{
280 struct s3c2410fb_info *fbi = info->par; 281 struct s3c2410fb_info *fbi = info->par;
282 struct s3c2410fb_mach_info *mach_info = fbi->mach_info;
283 struct s3c2410fb_display *display = mach_info->displays +
284 fbi->current_display;
281 int hs; 285 int hs;
282 286
283 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK; 287 fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
@@ -287,9 +291,9 @@ static void s3c2410fb_activate_var(struct fb_info *info,
287 dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres); 291 dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
288 dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); 292 dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);
289 293
290 fbi->regs.lcdcon1 |= fbi->mach_info->type; 294 fbi->regs.lcdcon1 |= display->type;
291 295
292 if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) 296 if (display->type == S3C2410_LCDCON1_TFT)
293 switch (var->bits_per_pixel) { 297 switch (var->bits_per_pixel) {
294 case 1: 298 case 1:
295 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP; 299 fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
@@ -338,7 +342,7 @@ static void s3c2410fb_activate_var(struct fb_info *info,
338 342
339 /* check to see if we need to update sync/borders */ 343 /* check to see if we need to update sync/borders */
340 344
341 if (!fbi->mach_info->fixed_syncs) { 345 if (!mach_info->fixed_syncs) {
342 dprintk("setting vert: up=%d, low=%d, sync=%d\n", 346 dprintk("setting vert: up=%d, low=%d, sync=%d\n",
343 var->upper_margin, var->lower_margin, var->vsync_len); 347 var->upper_margin, var->lower_margin, var->vsync_len);
344 348
@@ -363,7 +367,7 @@ static void s3c2410fb_activate_var(struct fb_info *info,
363 fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff); 367 fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff);
364 fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1); 368 fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1);
365 369
366 switch (fbi->mach_info->type) { 370 switch (display->type) {
367 case S3C2410_LCDCON1_DSCAN4: 371 case S3C2410_LCDCON1_DSCAN4:
368 case S3C2410_LCDCON1_STN8: 372 case S3C2410_LCDCON1_STN8:
369 hs = var->xres / 8; 373 hs = var->xres / 8;
@@ -388,7 +392,7 @@ static void s3c2410fb_activate_var(struct fb_info *info,
388 if (var->pixclock > 0) { 392 if (var->pixclock > 0) {
389 int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock); 393 int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock);
390 394
391 if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) { 395 if (display->type == S3C2410_LCDCON1_TFT) {
392 clkdiv = (clkdiv / 2) - 1; 396 clkdiv = (clkdiv / 2) - 1;
393 if (clkdiv < 0) 397 if (clkdiv < 0)
394 clkdiv = 0; 398 clkdiv = 0;
@@ -750,6 +754,7 @@ static char driver_name[] = "s3c2410fb";
750static int __init s3c2410fb_probe(struct platform_device *pdev) 754static int __init s3c2410fb_probe(struct platform_device *pdev)
751{ 755{
752 struct s3c2410fb_info *info; 756 struct s3c2410fb_info *info;
757 struct s3c2410fb_display *display;
753 struct fb_info *fbinfo; 758 struct fb_info *fbinfo;
754 struct s3c2410fb_hw *mregs; 759 struct s3c2410fb_hw *mregs;
755 struct resource *res; 760 struct resource *res;
@@ -766,7 +771,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
766 return -EINVAL; 771 return -EINVAL;
767 } 772 }
768 773
769 mregs = &mach_info->regs; 774 display = mach_info->displays + mach_info->default_display;
775 mregs = &display->regs;
770 776
771 irq = platform_get_irq(pdev, 0); 777 irq = platform_get_irq(pdev, 0);
772 if (irq < 0) { 778 if (irq < 0) {
@@ -809,7 +815,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
809 815
810 strcpy(fbinfo->fix.id, driver_name); 816 strcpy(fbinfo->fix.id, driver_name);
811 817
812 memcpy(&info->regs, &mach_info->regs, sizeof(info->regs)); 818 memcpy(&info->regs, &display->regs, sizeof(info->regs));
813 819
814 /* Stop the video and unset ENVID if set */ 820 /* Stop the video and unset ENVID if set */
815 info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID; 821 info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
@@ -817,6 +823,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
817 writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1); 823 writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);
818 824
819 info->mach_info = pdev->dev.platform_data; 825 info->mach_info = pdev->dev.platform_data;
826 info->current_display = mach_info->default_display;
820 827
821 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; 828 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
822 fbinfo->fix.type_aux = 0; 829 fbinfo->fix.type_aux = 0;
@@ -827,8 +834,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
827 834
828 fbinfo->var.nonstd = 0; 835 fbinfo->var.nonstd = 0;
829 fbinfo->var.activate = FB_ACTIVATE_NOW; 836 fbinfo->var.activate = FB_ACTIVATE_NOW;
830 fbinfo->var.height = mach_info->height; 837 fbinfo->var.height = display->height;
831 fbinfo->var.width = mach_info->width; 838 fbinfo->var.width = display->width;
832 fbinfo->var.accel_flags = 0; 839 fbinfo->var.accel_flags = 0;
833 fbinfo->var.vmode = FB_VMODE_NONINTERLACED; 840 fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
834 841
@@ -836,11 +843,11 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
836 fbinfo->flags = FBINFO_FLAG_DEFAULT; 843 fbinfo->flags = FBINFO_FLAG_DEFAULT;
837 fbinfo->pseudo_palette = &info->pseudo_pal; 844 fbinfo->pseudo_palette = &info->pseudo_pal;
838 845
839 fbinfo->var.xres = mach_info->xres.defval; 846 fbinfo->var.xres = display->xres;
840 fbinfo->var.xres_virtual = mach_info->xres.defval; 847 fbinfo->var.xres_virtual = display->xres;
841 fbinfo->var.yres = mach_info->yres.defval; 848 fbinfo->var.yres = display->yres;
842 fbinfo->var.yres_virtual = mach_info->yres.defval; 849 fbinfo->var.yres_virtual = display->yres;
843 fbinfo->var.bits_per_pixel = mach_info->bpp.defval; 850 fbinfo->var.bits_per_pixel = display->bpp;
844 851
845 fbinfo->var.upper_margin = 852 fbinfo->var.upper_margin =
846 S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1; 853 S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1;
@@ -864,9 +871,17 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
864 fbinfo->var.green.length = 6; 871 fbinfo->var.green.length = 6;
865 fbinfo->var.blue.length = 5; 872 fbinfo->var.blue.length = 5;
866 fbinfo->var.transp.length = 0; 873 fbinfo->var.transp.length = 0;
867 fbinfo->fix.smem_len = mach_info->xres.max * 874
868 mach_info->yres.max * 875 /* find maximum required memory size for display */
869 mach_info->bpp.max / 8; 876 for (i = 0; i < mach_info->num_displays; i++) {
877 unsigned long smem_len = mach_info->displays[i].xres;
878
879 smem_len *= mach_info->displays[i].yres;
880 smem_len *= mach_info->displays[i].bpp;
881 smem_len >>= 3;
882 if (fbinfo->fix.smem_len < smem_len)
883 fbinfo->fix.smem_len = smem_len;
884 }
870 885
871 for (i = 0; i < 256; i++) 886 for (i = 0; i < 256; i++)
872 info->palette_buffer[i] = PALETTE_BUFF_CLEAR; 887 info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index eec77080f2c5..9e86fffccb32 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -34,6 +34,8 @@ struct s3c2410fb_info {
34 34
35 struct s3c2410fb_mach_info *mach_info; 35 struct s3c2410fb_mach_info *mach_info;
36 36
37 unsigned current_display;
38
37 /* raw memory addresses */ 39 /* raw memory addresses */
38 dma_addr_t map_dma; /* physical */ 40 dma_addr_t map_dma; /* physical */
39 u_char * map_cpu; /* virtual */ 41 u_char * map_cpu; /* virtual */