diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2007-10-16 04:28:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:16 -0400 |
commit | 09fe75f6f934597f765748342ca6fb378ee7ecdb (patch) | |
tree | 55a3ab7bf52400be136ec533cd5ebda4336fcd07 /drivers/video/s3c2410fb.c | |
parent | 110c1fa75463c4f327e9fc491e9a27e938800d96 (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/s3c2410fb.c')
-rw-r--r-- | drivers/video/s3c2410fb.c | 83 |
1 files changed, 49 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"; | |||
750 | static int __init s3c2410fb_probe(struct platform_device *pdev) | 754 | static 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; |