diff options
-rw-r--r-- | arch/arm/mach-shmobile/board-ag5evm.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-ap4evb.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 4 | ||||
-rw-r--r-- | arch/sh/boards/mach-ap325rxa/setup.c | 2 | ||||
-rw-r--r-- | arch/sh/boards/mach-ecovec24/setup.c | 2 | ||||
-rw-r--r-- | arch/sh/boards/mach-kfr2r09/setup.c | 2 | ||||
-rw-r--r-- | arch/sh/boards/mach-migor/setup.c | 4 | ||||
-rw-r--r-- | arch/sh/boards/mach-se/7724/setup.c | 2 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 360 | ||||
-rw-r--r-- | include/video/sh_mobile_lcdc.h | 4 |
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 | ||
219 | static 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 | |||
236 | static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) | ||
237 | { | ||
238 | return var->grayscale > 1; | ||
239 | } | ||
240 | |||
241 | static 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 | |||
218 | static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) | 260 | static 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 | ||
850 | static void sh_mobile_lcdc_fillrect(struct fb_info *info, | 909 | static 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 | ||
175 | struct sh_mobile_lcdc_chan_cfg { | 175 | struct 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 | ||