diff options
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 125 |
1 files changed, 105 insertions, 20 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 9bcc61b4ef14..aa4fe993b6da 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <asm/atomic.h> | 27 | #include <asm/atomic.h> |
28 | 28 | ||
29 | #include "sh_mobile_lcdcfb.h" | 29 | #include "sh_mobile_lcdcfb.h" |
30 | #include "sh_mobile_meram.h" | ||
30 | 31 | ||
31 | #define SIDE_B_OFFSET 0x1000 | 32 | #define SIDE_B_OFFSET 0x1000 |
32 | #define MIRROR_OFFSET 0x2000 | 33 | #define MIRROR_OFFSET 0x2000 |
@@ -143,6 +144,7 @@ struct sh_mobile_lcdc_priv { | |||
143 | unsigned long saved_shared_regs[NR_SHARED_REGS]; | 144 | unsigned long saved_shared_regs[NR_SHARED_REGS]; |
144 | int started; | 145 | int started; |
145 | int forced_bpp; /* 2 channel LCDC must share bpp setting */ | 146 | int forced_bpp; /* 2 channel LCDC must share bpp setting */ |
147 | struct sh_mobile_meram_info *meram_dev; | ||
146 | }; | 148 | }; |
147 | 149 | ||
148 | static bool banked(int reg_nr) | 150 | static bool banked(int reg_nr) |
@@ -469,7 +471,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
469 | int bpp = 0; | 471 | int bpp = 0; |
470 | unsigned long ldddsr; | 472 | unsigned long ldddsr; |
471 | int k, m; | 473 | int k, m; |
472 | int ret = 0; | ||
473 | 474 | ||
474 | /* enable clocks before accessing the hardware */ | 475 | /* enable clocks before accessing the hardware */ |
475 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 476 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
@@ -538,11 +539,12 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
538 | lcdc_write_chan(ch, LDPMR, 0); | 539 | lcdc_write_chan(ch, LDPMR, 0); |
539 | 540 | ||
540 | board_cfg = &ch->cfg.board_cfg; | 541 | board_cfg = &ch->cfg.board_cfg; |
541 | if (board_cfg->setup_sys) | 542 | if (board_cfg->setup_sys) { |
542 | ret = board_cfg->setup_sys(board_cfg->board_data, ch, | 543 | int ret = board_cfg->setup_sys(board_cfg->board_data, |
543 | &sh_mobile_lcdc_sys_bus_ops); | 544 | ch, &sh_mobile_lcdc_sys_bus_ops); |
544 | if (ret) | 545 | if (ret) |
545 | return ret; | 546 | return ret; |
547 | } | ||
546 | } | 548 | } |
547 | 549 | ||
548 | /* word and long word swap */ | 550 | /* word and long word swap */ |
@@ -564,6 +566,9 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
564 | } | 566 | } |
565 | 567 | ||
566 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 568 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
569 | unsigned long base_addr_y; | ||
570 | unsigned long base_addr_c = 0; | ||
571 | int pitch; | ||
567 | ch = &priv->ch[k]; | 572 | ch = &priv->ch[k]; |
568 | 573 | ||
569 | if (!priv->ch[k].enabled) | 574 | if (!priv->ch[k].enabled) |
@@ -598,16 +603,67 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
598 | } | 603 | } |
599 | lcdc_write_chan(ch, LDDFR, tmp); | 604 | lcdc_write_chan(ch, LDDFR, tmp); |
600 | 605 | ||
606 | base_addr_y = ch->info->fix.smem_start; | ||
607 | base_addr_c = base_addr_y + | ||
608 | ch->info->var.xres * | ||
609 | ch->info->var.yres_virtual; | ||
610 | pitch = ch->info->fix.line_length; | ||
611 | |||
612 | /* test if we can enable meram */ | ||
613 | if (ch->cfg.meram_cfg && priv->meram_dev) { | ||
614 | struct sh_mobile_meram_cfg *cfg; | ||
615 | struct sh_mobile_meram_info *mdev; | ||
616 | unsigned long icb_addr_y, icb_addr_c; | ||
617 | int icb_pitch; | ||
618 | int pf; | ||
619 | |||
620 | cfg = ch->cfg.meram_cfg; | ||
621 | mdev = priv->meram_dev; | ||
622 | /* we need to de-init configured ICBs before we | ||
623 | * we can re-initialize them. | ||
624 | */ | ||
625 | if (ch->meram_enabled) | ||
626 | mdev->ops->meram_unregister(mdev, cfg); | ||
627 | |||
628 | ch->meram_enabled = 0; | ||
629 | |||
630 | if (ch->info->var.nonstd) { | ||
631 | if (ch->info->var.bits_per_pixel == 24) | ||
632 | pf = SH_MOBILE_MERAM_PF_NV24; | ||
633 | else | ||
634 | pf = SH_MOBILE_MERAM_PF_NV; | ||
635 | } else { | ||
636 | pf = SH_MOBILE_MERAM_PF_RGB; | ||
637 | } | ||
638 | |||
639 | ret = mdev->ops->meram_register(mdev, cfg, pitch, | ||
640 | ch->info->var.yres, | ||
641 | pf, | ||
642 | base_addr_y, | ||
643 | base_addr_c, | ||
644 | &icb_addr_y, | ||
645 | &icb_addr_c, | ||
646 | &icb_pitch); | ||
647 | if (!ret) { | ||
648 | /* set LDSA1R value */ | ||
649 | base_addr_y = icb_addr_y; | ||
650 | pitch = icb_pitch; | ||
651 | |||
652 | /* set LDSA2R value if required */ | ||
653 | if (base_addr_c) | ||
654 | base_addr_c = icb_addr_c; | ||
655 | |||
656 | ch->meram_enabled = 1; | ||
657 | } | ||
658 | } | ||
659 | |||
601 | /* point out our frame buffer */ | 660 | /* point out our frame buffer */ |
602 | lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); | 661 | lcdc_write_chan(ch, LDSA1R, base_addr_y); |
603 | if (ch->info->var.nonstd) | 662 | if (ch->info->var.nonstd) |
604 | lcdc_write_chan(ch, LDSA2R, | 663 | lcdc_write_chan(ch, LDSA2R, base_addr_c); |
605 | ch->info->fix.smem_start + | ||
606 | ch->info->var.xres * | ||
607 | ch->info->var.yres_virtual); | ||
608 | 664 | ||
609 | /* set line size */ | 665 | /* set line size */ |
610 | lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); | 666 | lcdc_write_chan(ch, LDMLSR, pitch); |
611 | 667 | ||
612 | /* setup deferred io if SYS bus */ | 668 | /* setup deferred io if SYS bus */ |
613 | tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; | 669 | tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; |
@@ -692,6 +748,17 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
692 | board_cfg->display_off(board_cfg->board_data); | 748 | board_cfg->display_off(board_cfg->board_data); |
693 | module_put(board_cfg->owner); | 749 | module_put(board_cfg->owner); |
694 | } | 750 | } |
751 | |||
752 | /* disable the meram */ | ||
753 | if (ch->meram_enabled) { | ||
754 | struct sh_mobile_meram_cfg *cfg; | ||
755 | struct sh_mobile_meram_info *mdev; | ||
756 | cfg = ch->cfg.meram_cfg; | ||
757 | mdev = priv->meram_dev; | ||
758 | mdev->ops->meram_unregister(mdev, cfg); | ||
759 | ch->meram_enabled = 0; | ||
760 | } | ||
761 | |||
695 | } | 762 | } |
696 | 763 | ||
697 | /* stop the lcdc */ | 764 | /* stop the lcdc */ |
@@ -875,9 +942,29 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
875 | } else | 942 | } else |
876 | base_addr_c = 0; | 943 | base_addr_c = 0; |
877 | 944 | ||
878 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); | 945 | if (!ch->meram_enabled) { |
879 | if (base_addr_c) | 946 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); |
880 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | 947 | if (base_addr_c) |
948 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | ||
949 | } else { | ||
950 | struct sh_mobile_meram_cfg *cfg; | ||
951 | struct sh_mobile_meram_info *mdev; | ||
952 | unsigned long icb_addr_y, icb_addr_c; | ||
953 | int ret; | ||
954 | |||
955 | cfg = ch->cfg.meram_cfg; | ||
956 | mdev = priv->meram_dev; | ||
957 | ret = mdev->ops->meram_update(mdev, cfg, | ||
958 | base_addr_y, base_addr_c, | ||
959 | &icb_addr_y, &icb_addr_c); | ||
960 | if (ret) | ||
961 | return ret; | ||
962 | |||
963 | lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y); | ||
964 | if (icb_addr_c) | ||
965 | lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c); | ||
966 | |||
967 | } | ||
881 | 968 | ||
882 | if (lcdc_chan_is_sublcd(ch)) | 969 | if (lcdc_chan_is_sublcd(ch)) |
883 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); | 970 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); |
@@ -1288,7 +1375,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, | |||
1288 | struct fb_info *info = event->info; | 1375 | struct fb_info *info = event->info; |
1289 | struct sh_mobile_lcdc_chan *ch = info->par; | 1376 | struct sh_mobile_lcdc_chan *ch = info->par; |
1290 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; | 1377 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; |
1291 | int ret; | ||
1292 | 1378 | ||
1293 | if (&ch->lcdc->notifier != nb) | 1379 | if (&ch->lcdc->notifier != nb) |
1294 | return NOTIFY_DONE; | 1380 | return NOTIFY_DONE; |
@@ -1302,7 +1388,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, | |||
1302 | board_cfg->display_off(board_cfg->board_data); | 1388 | board_cfg->display_off(board_cfg->board_data); |
1303 | module_put(board_cfg->owner); | 1389 | module_put(board_cfg->owner); |
1304 | } | 1390 | } |
1305 | pm_runtime_put(info->device); | ||
1306 | sh_mobile_lcdc_stop(ch->lcdc); | 1391 | sh_mobile_lcdc_stop(ch->lcdc); |
1307 | break; | 1392 | break; |
1308 | case FB_EVENT_RESUME: | 1393 | case FB_EVENT_RESUME: |
@@ -1316,9 +1401,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, | |||
1316 | module_put(board_cfg->owner); | 1401 | module_put(board_cfg->owner); |
1317 | } | 1402 | } |
1318 | 1403 | ||
1319 | ret = sh_mobile_lcdc_start(ch->lcdc); | 1404 | sh_mobile_lcdc_start(ch->lcdc); |
1320 | if (!ret) | ||
1321 | pm_runtime_get_sync(info->device); | ||
1322 | } | 1405 | } |
1323 | 1406 | ||
1324 | return NOTIFY_OK; | 1407 | return NOTIFY_OK; |
@@ -1420,6 +1503,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1420 | goto err1; | 1503 | goto err1; |
1421 | } | 1504 | } |
1422 | 1505 | ||
1506 | priv->meram_dev = pdata->meram_dev; | ||
1507 | |||
1423 | for (i = 0; i < j; i++) { | 1508 | for (i = 0; i < j; i++) { |
1424 | struct fb_var_screeninfo *var; | 1509 | struct fb_var_screeninfo *var; |
1425 | const struct fb_videomode *lcd_cfg, *max_cfg = NULL; | 1510 | const struct fb_videomode *lcd_cfg, *max_cfg = NULL; |