aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-shmobile/board-ag5evm.c2
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c4
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c4
-rw-r--r--arch/sh/boards/mach-ap325rxa/setup.c2
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c2
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c2
-rw-r--r--arch/sh/boards/mach-migor/setup.c4
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c2
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c360
-rw-r--r--include/video/sh_mobile_lcdc.h4
10 files changed, 253 insertions, 133 deletions
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 7e3dd7326827..80319f214765 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -271,7 +271,7 @@ static struct sh_mobile_lcdc_info lcdc0_info = {
271 .flags = LCDC_FLAGS_DWPOL, 271 .flags = LCDC_FLAGS_DWPOL,
272 .lcd_size_cfg.width = 44, 272 .lcd_size_cfg.width = 44,
273 .lcd_size_cfg.height = 79, 273 .lcd_size_cfg.height = 79,
274 .bpp = 16, 274 .fourcc = V4L2_PIX_FMT_RGB565,
275 .lcd_cfg = lcdc0_modes, 275 .lcd_cfg = lcdc0_modes,
276 .num_cfg = ARRAY_SIZE(lcdc0_modes), 276 .num_cfg = ARRAY_SIZE(lcdc0_modes),
277 .board_cfg = { 277 .board_cfg = {
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 904b608d1aa3..42b4dda57a79 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -491,7 +491,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
491 .meram_dev = &meram_info, 491 .meram_dev = &meram_info,
492 .ch[0] = { 492 .ch[0] = {
493 .chan = LCDC_CHAN_MAINLCD, 493 .chan = LCDC_CHAN_MAINLCD,
494 .bpp = 16, 494 .fourcc = V4L2_PIX_FMT_RGB565,
495 .lcd_cfg = ap4evb_lcdc_modes, 495 .lcd_cfg = ap4evb_lcdc_modes,
496 .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes), 496 .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
497 .meram_cfg = &lcd_meram_cfg, 497 .meram_cfg = &lcd_meram_cfg,
@@ -813,7 +813,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
813 .meram_dev = &meram_info, 813 .meram_dev = &meram_info,
814 .ch[0] = { 814 .ch[0] = {
815 .chan = LCDC_CHAN_MAINLCD, 815 .chan = LCDC_CHAN_MAINLCD,
816 .bpp = 16, 816 .fourcc = V4L2_PIX_FMT_RGB565,
817 .interface_type = RGB24, 817 .interface_type = RGB24,
818 .clock_divider = 1, 818 .clock_divider = 1,
819 .flags = LCDC_FLAGS_DWPOL, 819 .flags = LCDC_FLAGS_DWPOL,
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 9c5e598e0e3d..7db6a1712af5 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -388,7 +388,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
388 .clock_source = LCDC_CLK_BUS, 388 .clock_source = LCDC_CLK_BUS,
389 .ch[0] = { 389 .ch[0] = {
390 .chan = LCDC_CHAN_MAINLCD, 390 .chan = LCDC_CHAN_MAINLCD,
391 .bpp = 16, 391 .fourcc = V4L2_PIX_FMT_RGB565,
392 .lcd_cfg = mackerel_lcdc_modes, 392 .lcd_cfg = mackerel_lcdc_modes,
393 .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes), 393 .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes),
394 .interface_type = RGB24, 394 .interface_type = RGB24,
@@ -451,7 +451,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
451 .clock_source = LCDC_CLK_EXTERNAL, 451 .clock_source = LCDC_CLK_EXTERNAL,
452 .ch[0] = { 452 .ch[0] = {
453 .chan = LCDC_CHAN_MAINLCD, 453 .chan = LCDC_CHAN_MAINLCD,
454 .bpp = 16, 454 .fourcc = V4L2_PIX_FMT_RGB565,
455 .interface_type = RGB24, 455 .interface_type = RGB24,
456 .clock_divider = 1, 456 .clock_divider = 1,
457 .flags = LCDC_FLAGS_DWPOL, 457 .flags = LCDC_FLAGS_DWPOL,
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 7030f4c8cf11..7977911e72cf 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -207,7 +207,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
207 .clock_source = LCDC_CLK_EXTERNAL, 207 .clock_source = LCDC_CLK_EXTERNAL,
208 .ch[0] = { 208 .ch[0] = {
209 .chan = LCDC_CHAN_MAINLCD, 209 .chan = LCDC_CHAN_MAINLCD,
210 .bpp = 16, 210 .fourcc = V4L2_PIX_FMT_RGB565,
211 .interface_type = RGB18, 211 .interface_type = RGB18,
212 .clock_divider = 1, 212 .clock_divider = 1,
213 .lcd_cfg = ap325rxa_lcdc_modes, 213 .lcd_cfg = ap325rxa_lcdc_modes,
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 92ddce4b3456..1d4a706ed6ef 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -330,7 +330,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
330 .ch[0] = { 330 .ch[0] = {
331 .interface_type = RGB18, 331 .interface_type = RGB18,
332 .chan = LCDC_CHAN_MAINLCD, 332 .chan = LCDC_CHAN_MAINLCD,
333 .bpp = 16, 333 .fourcc = V4L2_PIX_FMT_RGB565,
334 .lcd_size_cfg = { /* 7.0 inch */ 334 .lcd_size_cfg = { /* 7.0 inch */
335 .width = 152, 335 .width = 152,
336 .height = 91, 336 .height = 91,
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index f65271a8d075..208c9b040263 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -146,7 +146,7 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = {
146 .clock_source = LCDC_CLK_BUS, 146 .clock_source = LCDC_CLK_BUS,
147 .ch[0] = { 147 .ch[0] = {
148 .chan = LCDC_CHAN_MAINLCD, 148 .chan = LCDC_CHAN_MAINLCD,
149 .bpp = 16, 149 .fourcc = V4L2_PIX_FMT_RGB565,
150 .interface_type = SYS18, 150 .interface_type = SYS18,
151 .clock_divider = 6, 151 .clock_divider = 6,
152 .flags = LCDC_FLAGS_DWPOL, 152 .flags = LCDC_FLAGS_DWPOL,
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index e4c81195929c..ccf61fb99853 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -244,7 +244,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
244 .clock_source = LCDC_CLK_BUS, 244 .clock_source = LCDC_CLK_BUS,
245 .ch[0] = { 245 .ch[0] = {
246 .chan = LCDC_CHAN_MAINLCD, 246 .chan = LCDC_CHAN_MAINLCD,
247 .bpp = 16, 247 .fourcc = V4L2_PIX_FMT_RGB565,
248 .interface_type = RGB16, 248 .interface_type = RGB16,
249 .clock_divider = 2, 249 .clock_divider = 2,
250 .lcd_cfg = migor_lcd_modes, 250 .lcd_cfg = migor_lcd_modes,
@@ -258,7 +258,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
258 .clock_source = LCDC_CLK_PERIPHERAL, 258 .clock_source = LCDC_CLK_PERIPHERAL,
259 .ch[0] = { 259 .ch[0] = {
260 .chan = LCDC_CHAN_MAINLCD, 260 .chan = LCDC_CHAN_MAINLCD,
261 .bpp = 16, 261 .fourcc = V4L2_PIX_FMT_RGB565,
262 .interface_type = SYS16A, 262 .interface_type = SYS16A,
263 .clock_divider = 10, 263 .clock_divider = 10,
264 .lcd_cfg = migor_lcd_modes, 264 .lcd_cfg = migor_lcd_modes,
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index b747c0ab9264..3aab70cd39e3 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -179,7 +179,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
179 .clock_source = LCDC_CLK_EXTERNAL, 179 .clock_source = LCDC_CLK_EXTERNAL,
180 .ch[0] = { 180 .ch[0] = {
181 .chan = LCDC_CHAN_MAINLCD, 181 .chan = LCDC_CHAN_MAINLCD,
182 .bpp = 16, 182 .fourcc = V4L2_PIX_FMT_RGB565,
183 .clock_divider = 1, 183 .clock_divider = 1,
184 .lcd_size_cfg = { /* 7.0 inch */ 184 .lcd_size_cfg = { /* 7.0 inch */
185 .width = 152, 185 .width = 152,
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index a264ebf971a0..aac5b369d73c 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -17,6 +17,7 @@
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/dma-mapping.h> 18#include <linux/dma-mapping.h>
19#include <linux/interrupt.h> 19#include <linux/interrupt.h>
20#include <linux/videodev2.h>
20#include <linux/vmalloc.h> 21#include <linux/vmalloc.h>
21#include <linux/ioctl.h> 22#include <linux/ioctl.h>
22#include <linux/slab.h> 23#include <linux/slab.h>
@@ -102,7 +103,7 @@ struct sh_mobile_lcdc_priv {
102 struct sh_mobile_lcdc_chan ch[2]; 103 struct sh_mobile_lcdc_chan ch[2];
103 struct notifier_block notifier; 104 struct notifier_block notifier;
104 int started; 105 int started;
105 int forced_bpp; /* 2 channel LCDC must share bpp setting */ 106 int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
106 struct sh_mobile_meram_info *meram_dev; 107 struct sh_mobile_meram_info *meram_dev;
107}; 108};
108 109
@@ -215,6 +216,47 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
215 lcdc_sys_read_data, 216 lcdc_sys_read_data,
216}; 217};
217 218
219static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
220{
221 if (var->grayscale > 1)
222 return var->grayscale;
223
224 switch (var->bits_per_pixel) {
225 case 16:
226 return V4L2_PIX_FMT_RGB565;
227 case 24:
228 return V4L2_PIX_FMT_BGR24;
229 case 32:
230 return V4L2_PIX_FMT_BGR32;
231 default:
232 return 0;
233 }
234}
235
236static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
237{
238 return var->grayscale > 1;
239}
240
241static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
242{
243 if (var->grayscale <= 1)
244 return false;
245
246 switch (var->grayscale) {
247 case V4L2_PIX_FMT_NV12:
248 case V4L2_PIX_FMT_NV21:
249 case V4L2_PIX_FMT_NV16:
250 case V4L2_PIX_FMT_NV61:
251 case V4L2_PIX_FMT_NV24:
252 case V4L2_PIX_FMT_NV42:
253 return true;
254
255 default:
256 return false;
257 }
258}
259
218static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) 260static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
219{ 261{
220 if (atomic_inc_and_test(&priv->hw_usecnt)) { 262 if (atomic_inc_and_test(&priv->hw_usecnt)) {
@@ -435,7 +477,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
435{ 477{
436 struct sh_mobile_lcdc_chan *ch; 478 struct sh_mobile_lcdc_chan *ch;
437 unsigned long tmp; 479 unsigned long tmp;
438 int bpp = 0;
439 int k, m; 480 int k, m;
440 481
441 /* Enable LCDC channels. Read data from external memory, avoid using the 482 /* Enable LCDC channels. Read data from external memory, avoid using the
@@ -454,9 +495,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
454 if (!ch->enabled) 495 if (!ch->enabled)
455 continue; 496 continue;
456 497
457 if (!bpp)
458 bpp = ch->info->var.bits_per_pixel;
459
460 /* Power supply */ 498 /* Power supply */
461 lcdc_write_chan(ch, LDPMR, 0); 499 lcdc_write_chan(ch, LDPMR, 0);
462 500
@@ -487,31 +525,37 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
487 525
488 sh_mobile_lcdc_geometry(ch); 526 sh_mobile_lcdc_geometry(ch);
489 527
490 if (ch->info->var.nonstd) { 528 switch (sh_mobile_format_fourcc(&ch->info->var)) {
491 tmp = (ch->info->var.nonstd << 16); 529 case V4L2_PIX_FMT_RGB565:
492 switch (ch->info->var.bits_per_pixel) { 530 tmp = LDDFR_PKF_RGB16;
493 case 12: 531 break;
494 tmp |= LDDFR_YF_420; 532 case V4L2_PIX_FMT_BGR24:
495 break; 533 tmp = LDDFR_PKF_RGB24;
496 case 16: 534 break;
497 tmp |= LDDFR_YF_422; 535 case V4L2_PIX_FMT_BGR32:
498 break; 536 tmp = LDDFR_PKF_ARGB32;
499 case 24: 537 break;
500 default: 538 case V4L2_PIX_FMT_NV12:
501 tmp |= LDDFR_YF_444; 539 case V4L2_PIX_FMT_NV21:
502 break; 540 tmp = LDDFR_CC | LDDFR_YF_420;
503 } 541 break;
504 } else { 542 case V4L2_PIX_FMT_NV16:
505 switch (ch->info->var.bits_per_pixel) { 543 case V4L2_PIX_FMT_NV61:
506 case 16: 544 tmp = LDDFR_CC | LDDFR_YF_422;
507 tmp = LDDFR_PKF_RGB16; 545 break;
508 break; 546 case V4L2_PIX_FMT_NV24:
509 case 24: 547 case V4L2_PIX_FMT_NV42:
510 tmp = LDDFR_PKF_RGB24; 548 tmp = LDDFR_CC | LDDFR_YF_444;
549 break;
550 }
551
552 if (sh_mobile_format_is_yuv(&ch->info->var)) {
553 switch (ch->info->var.colorspace) {
554 case V4L2_COLORSPACE_REC709:
555 tmp |= LDDFR_CF1;
511 break; 556 break;
512 case 32: 557 case V4L2_COLORSPACE_JPEG:
513 default: 558 tmp |= LDDFR_CF0;
514 tmp = LDDFR_PKF_ARGB32;
515 break; 559 break;
516 } 560 }
517 } 561 }
@@ -519,7 +563,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
519 lcdc_write_chan(ch, LDDFR, tmp); 563 lcdc_write_chan(ch, LDDFR, tmp);
520 lcdc_write_chan(ch, LDMLSR, ch->pitch); 564 lcdc_write_chan(ch, LDMLSR, ch->pitch);
521 lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); 565 lcdc_write_chan(ch, LDSA1R, ch->base_addr_y);
522 if (ch->info->var.nonstd) 566 if (sh_mobile_format_is_yuv(&ch->info->var))
523 lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); 567 lcdc_write_chan(ch, LDSA2R, ch->base_addr_c);
524 568
525 /* When using deferred I/O mode, configure the LCDC for one-shot 569 /* When using deferred I/O mode, configure the LCDC for one-shot
@@ -536,21 +580,23 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
536 } 580 }
537 581
538 /* Word and long word swap. */ 582 /* Word and long word swap. */
539 if (priv->ch[0].info->var.nonstd) 583 switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) {
584 case V4L2_PIX_FMT_RGB565:
585 case V4L2_PIX_FMT_NV21:
586 case V4L2_PIX_FMT_NV61:
587 case V4L2_PIX_FMT_NV42:
588 tmp = LDDDSR_LS | LDDDSR_WS;
589 break;
590 case V4L2_PIX_FMT_BGR24:
591 case V4L2_PIX_FMT_NV12:
592 case V4L2_PIX_FMT_NV16:
593 case V4L2_PIX_FMT_NV24:
540 tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; 594 tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
541 else { 595 break;
542 switch (bpp) { 596 case V4L2_PIX_FMT_BGR32:
543 case 16: 597 default:
544 tmp = LDDDSR_LS | LDDDSR_WS; 598 tmp = LDDDSR_LS;
545 break; 599 break;
546 case 24:
547 tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
548 break;
549 case 32:
550 default:
551 tmp = LDDDSR_LS;
552 break;
553 }
554 } 600 }
555 lcdc_write(priv, _LDDDSR, tmp); 601 lcdc_write(priv, _LDDDSR, tmp);
556 602
@@ -622,12 +668,24 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
622 ch->meram_enabled = 0; 668 ch->meram_enabled = 0;
623 } 669 }
624 670
625 if (!ch->info->var.nonstd) 671 switch (sh_mobile_format_fourcc(&ch->info->var)) {
626 pixelformat = SH_MOBILE_MERAM_PF_RGB; 672 case V4L2_PIX_FMT_NV12:
627 else if (ch->info->var.bits_per_pixel == 24) 673 case V4L2_PIX_FMT_NV21:
628 pixelformat = SH_MOBILE_MERAM_PF_NV24; 674 case V4L2_PIX_FMT_NV16:
629 else 675 case V4L2_PIX_FMT_NV61:
630 pixelformat = SH_MOBILE_MERAM_PF_NV; 676 pixelformat = SH_MOBILE_MERAM_PF_NV;
677 break;
678 case V4L2_PIX_FMT_NV24:
679 case V4L2_PIX_FMT_NV42:
680 pixelformat = SH_MOBILE_MERAM_PF_NV24;
681 break;
682 case V4L2_PIX_FMT_RGB565:
683 case V4L2_PIX_FMT_BGR24:
684 case V4L2_PIX_FMT_BGR32:
685 default:
686 pixelformat = SH_MOBILE_MERAM_PF_RGB;
687 break;
688 }
631 689
632 ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, 690 ret = mdev->ops->meram_register(mdev, cfg, ch->pitch,
633 ch->info->var.yres, pixelformat, 691 ch->info->var.yres, pixelformat,
@@ -845,6 +903,7 @@ static struct fb_fix_screeninfo sh_mobile_lcdc_fix = {
845 .xpanstep = 0, 903 .xpanstep = 0,
846 .ypanstep = 1, 904 .ypanstep = 1,
847 .ywrapstep = 0, 905 .ywrapstep = 0,
906 .capabilities = FB_CAP_FOURCC,
848}; 907};
849 908
850static void sh_mobile_lcdc_fillrect(struct fb_info *info, 909static void sh_mobile_lcdc_fillrect(struct fb_info *info,
@@ -877,8 +936,9 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
877 unsigned long new_pan_offset; 936 unsigned long new_pan_offset;
878 unsigned long base_addr_y, base_addr_c; 937 unsigned long base_addr_y, base_addr_c;
879 unsigned long c_offset; 938 unsigned long c_offset;
939 bool yuv = sh_mobile_format_is_yuv(&info->var);
880 940
881 if (!info->var.nonstd) 941 if (!yuv)
882 new_pan_offset = var->yoffset * info->fix.line_length 942 new_pan_offset = var->yoffset * info->fix.line_length
883 + var->xoffset * (info->var.bits_per_pixel / 8); 943 + var->xoffset * (info->var.bits_per_pixel / 8);
884 else 944 else
@@ -892,7 +952,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
892 952
893 /* Set the source address for the next refresh */ 953 /* Set the source address for the next refresh */
894 base_addr_y = ch->dma_handle + new_pan_offset; 954 base_addr_y = ch->dma_handle + new_pan_offset;
895 if (info->var.nonstd) { 955 if (yuv) {
896 /* Set y offset */ 956 /* Set y offset */
897 c_offset = var->yoffset * info->fix.line_length 957 c_offset = var->yoffset * info->fix.line_length
898 * (info->var.bits_per_pixel - 8) / 8; 958 * (info->var.bits_per_pixel - 8) / 8;
@@ -900,7 +960,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
900 + info->var.xres * info->var.yres_virtual 960 + info->var.xres * info->var.yres_virtual
901 + c_offset; 961 + c_offset;
902 /* Set x offset */ 962 /* Set x offset */
903 if (info->var.bits_per_pixel == 24) 963 if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24)
904 base_addr_c += 2 * var->xoffset; 964 base_addr_c += 2 * var->xoffset;
905 else 965 else
906 base_addr_c += var->xoffset; 966 base_addr_c += var->xoffset;
@@ -924,7 +984,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
924 ch->base_addr_c = base_addr_c; 984 ch->base_addr_c = base_addr_c;
925 985
926 lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); 986 lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
927 if (info->var.nonstd) 987 if (yuv)
928 lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); 988 lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
929 989
930 if (lcdc_chan_is_sublcd(ch)) 990 if (lcdc_chan_is_sublcd(ch))
@@ -1100,51 +1160,84 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in
1100 if (var->yres_virtual < var->yres) 1160 if (var->yres_virtual < var->yres)
1101 var->yres_virtual = var->yres; 1161 var->yres_virtual = var->yres;
1102 1162
1103 if (var->bits_per_pixel <= 16) { /* RGB 565 */ 1163 if (sh_mobile_format_is_fourcc(var)) {
1104 var->bits_per_pixel = 16; 1164 switch (var->grayscale) {
1105 var->red.offset = 11; 1165 case V4L2_PIX_FMT_NV12:
1106 var->red.length = 5; 1166 case V4L2_PIX_FMT_NV21:
1107 var->green.offset = 5; 1167 var->bits_per_pixel = 12;
1108 var->green.length = 6; 1168 break;
1109 var->blue.offset = 0; 1169 case V4L2_PIX_FMT_RGB565:
1110 var->blue.length = 5; 1170 case V4L2_PIX_FMT_NV16:
1111 var->transp.offset = 0; 1171 case V4L2_PIX_FMT_NV61:
1112 var->transp.length = 0; 1172 var->bits_per_pixel = 16;
1113 } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ 1173 break;
1114 var->bits_per_pixel = 24; 1174 case V4L2_PIX_FMT_BGR24:
1115 var->red.offset = 16; 1175 case V4L2_PIX_FMT_NV24:
1116 var->red.length = 8; 1176 case V4L2_PIX_FMT_NV42:
1117 var->green.offset = 8; 1177 var->bits_per_pixel = 24;
1118 var->green.length = 8; 1178 break;
1119 var->blue.offset = 0; 1179 case V4L2_PIX_FMT_BGR32:
1120 var->blue.length = 8; 1180 var->bits_per_pixel = 32;
1121 var->transp.offset = 0; 1181 break;
1122 var->transp.length = 0; 1182 default:
1123 } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ 1183 return -EINVAL;
1124 var->bits_per_pixel = 32; 1184 }
1125 var->red.offset = 16; 1185
1126 var->red.length = 8; 1186 /* Default to RGB and JPEG color-spaces for RGB and YUV formats
1127 var->green.offset = 8; 1187 * respectively.
1128 var->green.length = 8; 1188 */
1129 var->blue.offset = 0; 1189 if (!sh_mobile_format_is_yuv(var))
1130 var->blue.length = 8; 1190 var->colorspace = V4L2_COLORSPACE_SRGB;
1131 var->transp.offset = 24; 1191 else if (var->colorspace != V4L2_COLORSPACE_REC709)
1132 var->transp.length = 8; 1192 var->colorspace = V4L2_COLORSPACE_JPEG;
1133 } else 1193 } else {
1134 return -EINVAL; 1194 if (var->bits_per_pixel <= 16) { /* RGB 565 */
1195 var->bits_per_pixel = 16;
1196 var->red.offset = 11;
1197 var->red.length = 5;
1198 var->green.offset = 5;
1199 var->green.length = 6;
1200 var->blue.offset = 0;
1201 var->blue.length = 5;
1202 var->transp.offset = 0;
1203 var->transp.length = 0;
1204 } else if (var->bits_per_pixel <= 24) { /* RGB 888 */
1205 var->bits_per_pixel = 24;
1206 var->red.offset = 16;
1207 var->red.length = 8;
1208 var->green.offset = 8;
1209 var->green.length = 8;
1210 var->blue.offset = 0;
1211 var->blue.length = 8;
1212 var->transp.offset = 0;
1213 var->transp.length = 0;
1214 } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */
1215 var->bits_per_pixel = 32;
1216 var->red.offset = 16;
1217 var->red.length = 8;
1218 var->green.offset = 8;
1219 var->green.length = 8;
1220 var->blue.offset = 0;
1221 var->blue.length = 8;
1222 var->transp.offset = 24;
1223 var->transp.length = 8;
1224 } else
1225 return -EINVAL;
1135 1226
1136 var->red.msb_right = 0; 1227 var->red.msb_right = 0;
1137 var->green.msb_right = 0; 1228 var->green.msb_right = 0;
1138 var->blue.msb_right = 0; 1229 var->blue.msb_right = 0;
1139 var->transp.msb_right = 0; 1230 var->transp.msb_right = 0;
1231 }
1140 1232
1141 /* Make sure we don't exceed our allocated memory. */ 1233 /* Make sure we don't exceed our allocated memory. */
1142 if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > 1234 if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
1143 info->fix.smem_len) 1235 info->fix.smem_len)
1144 return -EINVAL; 1236 return -EINVAL;
1145 1237
1146 /* only accept the forced_bpp for dual channel configurations */ 1238 /* only accept the forced_fourcc for dual channel configurations */
1147 if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel) 1239 if (p->forced_fourcc &&
1240 p->forced_fourcc != sh_mobile_format_fourcc(var))
1148 return -EINVAL; 1241 return -EINVAL;
1149 1242
1150 return 0; 1243 return 0;
@@ -1158,7 +1251,7 @@ static int sh_mobile_set_par(struct fb_info *info)
1158 1251
1159 sh_mobile_lcdc_stop(ch->lcdc); 1252 sh_mobile_lcdc_stop(ch->lcdc);
1160 1253
1161 if (info->var.nonstd) 1254 if (sh_mobile_format_is_yuv(&info->var))
1162 info->fix.line_length = info->var.xres; 1255 info->fix.line_length = info->var.xres;
1163 else 1256 else
1164 info->fix.line_length = info->var.xres 1257 info->fix.line_length = info->var.xres
@@ -1170,6 +1263,14 @@ static int sh_mobile_set_par(struct fb_info *info)
1170 info->fix.line_length = line_length; 1263 info->fix.line_length = line_length;
1171 } 1264 }
1172 1265
1266 if (sh_mobile_format_is_fourcc(&info->var)) {
1267 info->fix.type = FB_TYPE_FOURCC;
1268 info->fix.visual = FB_VISUAL_FOURCC;
1269 } else {
1270 info->fix.type = FB_TYPE_PACKED_PIXELS;
1271 info->fix.visual = FB_VISUAL_TRUECOLOR;
1272 }
1273
1173 return ret; 1274 return ret;
1174} 1275}
1175 1276
@@ -1464,9 +1565,9 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
1464 for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) { 1565 for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) {
1465 unsigned int size = mode->yres * mode->xres; 1566 unsigned int size = mode->yres * mode->xres;
1466 1567
1467 /* NV12 buffers must have even number of lines */ 1568 /* NV12/NV21 buffers must have even number of lines */
1468 if ((cfg->nonstd) && cfg->bpp == 12 && 1569 if ((cfg->fourcc == V4L2_PIX_FMT_NV12 ||
1469 (mode->yres & 0x1)) { 1570 cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) {
1470 dev_err(dev, "yres must be multiple of 2 for YCbCr420 " 1571 dev_err(dev, "yres must be multiple of 2 for YCbCr420 "
1471 "mode.\n"); 1572 "mode.\n");
1472 return -EINVAL; 1573 return -EINVAL;
@@ -1484,14 +1585,6 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
1484 dev_dbg(dev, "Found largest videomode %ux%u\n", 1585 dev_dbg(dev, "Found largest videomode %ux%u\n",
1485 max_mode->xres, max_mode->yres); 1586 max_mode->xres, max_mode->yres);
1486 1587
1487 /* Initialize fixed screen information. Restrict pan to 2 lines steps
1488 * for NV12.
1489 */
1490 info->fix = sh_mobile_lcdc_fix;
1491 info->fix.smem_len = max_size * 2 * cfg->bpp / 8;
1492 if (cfg->nonstd && cfg->bpp == 12)
1493 info->fix.ypanstep = 2;
1494
1495 /* Create the mode list. */ 1588 /* Create the mode list. */
1496 if (cfg->lcd_cfg == NULL) { 1589 if (cfg->lcd_cfg == NULL) {
1497 mode = &default_720p; 1590 mode = &default_720p;
@@ -1509,19 +1602,38 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
1509 */ 1602 */
1510 var = &info->var; 1603 var = &info->var;
1511 fb_videomode_to_var(var, mode); 1604 fb_videomode_to_var(var, mode);
1512 var->bits_per_pixel = cfg->bpp;
1513 var->width = cfg->lcd_size_cfg.width; 1605 var->width = cfg->lcd_size_cfg.width;
1514 var->height = cfg->lcd_size_cfg.height; 1606 var->height = cfg->lcd_size_cfg.height;
1515 var->yres_virtual = var->yres * 2; 1607 var->yres_virtual = var->yres * 2;
1516 var->activate = FB_ACTIVATE_NOW; 1608 var->activate = FB_ACTIVATE_NOW;
1517 1609
1610 switch (cfg->fourcc) {
1611 case V4L2_PIX_FMT_RGB565:
1612 var->bits_per_pixel = 16;
1613 break;
1614 case V4L2_PIX_FMT_BGR24:
1615 var->bits_per_pixel = 24;
1616 break;
1617 case V4L2_PIX_FMT_BGR32:
1618 var->bits_per_pixel = 32;
1619 break;
1620 default:
1621 var->grayscale = cfg->fourcc;
1622 break;
1623 }
1624
1625 /* Make sure the memory size check won't fail. smem_len is initialized
1626 * later based on var.
1627 */
1628 info->fix.smem_len = UINT_MAX;
1518 ret = sh_mobile_check_var(var, info); 1629 ret = sh_mobile_check_var(var, info);
1519 if (ret) 1630 if (ret)
1520 return ret; 1631 return ret;
1521 1632
1633 max_size = max_size * var->bits_per_pixel / 8 * 2;
1634
1522 /* Allocate frame buffer memory and color map. */ 1635 /* Allocate frame buffer memory and color map. */
1523 buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle, 1636 buf = dma_alloc_coherent(dev, max_size, &ch->dma_handle, GFP_KERNEL);
1524 GFP_KERNEL);
1525 if (!buf) { 1637 if (!buf) {
1526 dev_err(dev, "unable to allocate buffer\n"); 1638 dev_err(dev, "unable to allocate buffer\n");
1527 return -ENOMEM; 1639 return -ENOMEM;
@@ -1530,16 +1642,27 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
1530 ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); 1642 ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
1531 if (ret < 0) { 1643 if (ret < 0) {
1532 dev_err(dev, "unable to allocate cmap\n"); 1644 dev_err(dev, "unable to allocate cmap\n");
1533 dma_free_coherent(dev, info->fix.smem_len, 1645 dma_free_coherent(dev, max_size, buf, ch->dma_handle);
1534 buf, ch->dma_handle);
1535 return ret; 1646 return ret;
1536 } 1647 }
1537 1648
1649 /* Initialize fixed screen information. Restrict pan to 2 lines steps
1650 * for NV12 and NV21.
1651 */
1652 info->fix = sh_mobile_lcdc_fix;
1538 info->fix.smem_start = ch->dma_handle; 1653 info->fix.smem_start = ch->dma_handle;
1539 if (var->nonstd) 1654 info->fix.smem_len = max_size;
1655 if (cfg->fourcc == V4L2_PIX_FMT_NV12 ||
1656 cfg->fourcc == V4L2_PIX_FMT_NV21)
1657 info->fix.ypanstep = 2;
1658
1659 if (sh_mobile_format_is_yuv(var)) {
1540 info->fix.line_length = var->xres; 1660 info->fix.line_length = var->xres;
1541 else 1661 info->fix.visual = FB_VISUAL_FOURCC;
1542 info->fix.line_length = var->xres * (cfg->bpp / 8); 1662 } else {
1663 info->fix.line_length = var->xres * var->bits_per_pixel / 8;
1664 info->fix.visual = FB_VISUAL_TRUECOLOR;
1665 }
1543 1666
1544 info->screen_base = buf; 1667 info->screen_base = buf;
1545 info->device = dev; 1668 info->device = dev;
@@ -1626,9 +1749,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
1626 goto err1; 1749 goto err1;
1627 } 1750 }
1628 1751
1629 /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */ 1752 /* for dual channel LCDC (MAIN + SUB) force shared format setting */
1630 if (num_channels == 2) 1753 if (num_channels == 2)
1631 priv->forced_bpp = pdata->ch[0].bpp; 1754 priv->forced_fourcc = pdata->ch[0].fourcc;
1632 1755
1633 priv->base = ioremap_nocache(res->start, resource_size(res)); 1756 priv->base = ioremap_nocache(res->start, resource_size(res));
1634 if (!priv->base) 1757 if (!priv->base)
@@ -1675,13 +1798,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
1675 if (error < 0) 1798 if (error < 0)
1676 goto err1; 1799 goto err1;
1677 1800
1678 dev_info(info->dev, 1801 dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n",
1679 "registered %s/%s as %dx%d %dbpp.\n", 1802 pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
1680 pdev->name, 1803 "mainlcd" : "sublcd", info->var.xres, info->var.yres,
1681 (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? 1804 info->var.bits_per_pixel);
1682 "mainlcd" : "sublcd",
1683 info->var.xres, info->var.yres,
1684 ch->cfg.bpp);
1685 1805
1686 /* deferred io mode: disable clock to save power */ 1806 /* deferred io mode: disable clock to save power */
1687 if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) 1807 if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index 8101b726b48a..fe30b759c51e 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -174,7 +174,8 @@ struct sh_mobile_lcdc_bl_info {
174 174
175struct sh_mobile_lcdc_chan_cfg { 175struct sh_mobile_lcdc_chan_cfg {
176 int chan; 176 int chan;
177 int bpp; 177 int fourcc;
178 int colorspace;
178 int interface_type; /* selects RGBn or SYSn I/F, see above */ 179 int interface_type; /* selects RGBn or SYSn I/F, see above */
179 int clock_divider; 180 int clock_divider;
180 unsigned long flags; /* LCDC_FLAGS_... */ 181 unsigned long flags; /* LCDC_FLAGS_... */
@@ -184,7 +185,6 @@ struct sh_mobile_lcdc_chan_cfg {
184 struct sh_mobile_lcdc_board_cfg board_cfg; 185 struct sh_mobile_lcdc_board_cfg board_cfg;
185 struct sh_mobile_lcdc_bl_info bl_info; 186 struct sh_mobile_lcdc_bl_info bl_info;
186 struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ 187 struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
187 int nonstd;
188 struct sh_mobile_meram_cfg *meram_cfg; 188 struct sh_mobile_meram_cfg *meram_cfg;
189}; 189};
190 190