diff options
author | Damian <dhobsong@igel.co.jp> | 2011-05-18 07:10:07 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-05-23 03:06:24 -0400 |
commit | 7caa4342ca5b37d2d178b464c16badd4228b3b7b (patch) | |
tree | 0111e05278facfc0eb92c46b80c577d1e1e694e4 /drivers/video/sh_mobile_lcdcfb.c | |
parent | 71a8638480eb8fb6cfabe2ee9ca3fbc6e3453a14 (diff) |
sh_mobile_meram: MERAM framework for LCDC
Based on the patch by Takanari Hayama <taki@igel.co.jp>
Adds support framework necessary to use Media RAM (MERAM)
caching functionality with the LCDC. The MERAM is accessed
through up to 4 Interconnect Buffers (ICBs).
ICB numbers and MERAM address ranges to use are specified in
by filling in the .meram_cfg member of the LCDC platform data
Signed-off-by: Damian Hobson-Garcia <dhobsong@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 103 |
1 files changed, 94 insertions, 9 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 9bcc61b4ef14..3a2cbd18f91b 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) |
@@ -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,63 @@ 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 | pf = SH_MOBILE_MERAM_PF_NV; | ||
632 | else | ||
633 | pf = SH_MOBILE_MERAM_PF_RGB; | ||
634 | |||
635 | ret = mdev->ops->meram_register(mdev, cfg, pitch, | ||
636 | ch->info->var.yres, | ||
637 | pf, | ||
638 | base_addr_y, | ||
639 | base_addr_c, | ||
640 | &icb_addr_y, | ||
641 | &icb_addr_c, | ||
642 | &icb_pitch); | ||
643 | if (!ret) { | ||
644 | /* set LDSA1R value */ | ||
645 | base_addr_y = icb_addr_y; | ||
646 | pitch = icb_pitch; | ||
647 | |||
648 | /* set LDSA2R value if required */ | ||
649 | if (base_addr_c) | ||
650 | base_addr_c = icb_addr_c; | ||
651 | |||
652 | ch->meram_enabled = 1; | ||
653 | } | ||
654 | } | ||
655 | |||
601 | /* point out our frame buffer */ | 656 | /* point out our frame buffer */ |
602 | lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); | 657 | lcdc_write_chan(ch, LDSA1R, base_addr_y); |
603 | if (ch->info->var.nonstd) | 658 | if (ch->info->var.nonstd) |
604 | lcdc_write_chan(ch, LDSA2R, | 659 | 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 | 660 | ||
609 | /* set line size */ | 661 | /* set line size */ |
610 | lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); | 662 | lcdc_write_chan(ch, LDMLSR, pitch); |
611 | 663 | ||
612 | /* setup deferred io if SYS bus */ | 664 | /* setup deferred io if SYS bus */ |
613 | tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; | 665 | tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; |
@@ -692,6 +744,17 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
692 | board_cfg->display_off(board_cfg->board_data); | 744 | board_cfg->display_off(board_cfg->board_data); |
693 | module_put(board_cfg->owner); | 745 | module_put(board_cfg->owner); |
694 | } | 746 | } |
747 | |||
748 | /* disable the meram */ | ||
749 | if (ch->meram_enabled) { | ||
750 | struct sh_mobile_meram_cfg *cfg; | ||
751 | struct sh_mobile_meram_info *mdev; | ||
752 | cfg = ch->cfg.meram_cfg; | ||
753 | mdev = priv->meram_dev; | ||
754 | mdev->ops->meram_unregister(mdev, cfg); | ||
755 | ch->meram_enabled = 0; | ||
756 | } | ||
757 | |||
695 | } | 758 | } |
696 | 759 | ||
697 | /* stop the lcdc */ | 760 | /* stop the lcdc */ |
@@ -875,9 +938,29 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
875 | } else | 938 | } else |
876 | base_addr_c = 0; | 939 | base_addr_c = 0; |
877 | 940 | ||
878 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); | 941 | if (!ch->meram_enabled) { |
879 | if (base_addr_c) | 942 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); |
880 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | 943 | if (base_addr_c) |
944 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | ||
945 | } else { | ||
946 | struct sh_mobile_meram_cfg *cfg; | ||
947 | struct sh_mobile_meram_info *mdev; | ||
948 | unsigned long icb_addr_y, icb_addr_c; | ||
949 | int ret; | ||
950 | |||
951 | cfg = ch->cfg.meram_cfg; | ||
952 | mdev = priv->meram_dev; | ||
953 | ret = mdev->ops->meram_update(mdev, cfg, | ||
954 | base_addr_y, base_addr_c, | ||
955 | &icb_addr_y, &icb_addr_c); | ||
956 | if (ret) | ||
957 | return ret; | ||
958 | |||
959 | lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y); | ||
960 | if (icb_addr_c) | ||
961 | lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c); | ||
962 | |||
963 | } | ||
881 | 964 | ||
882 | if (lcdc_chan_is_sublcd(ch)) | 965 | if (lcdc_chan_is_sublcd(ch)) |
883 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); | 966 | lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS); |
@@ -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; |