diff options
Diffstat (limited to 'recipes/linux/linux-omap-pm/dss2/0065-VRFB-add-suspend-resume-functionality.patch')
-rw-r--r-- | recipes/linux/linux-omap-pm/dss2/0065-VRFB-add-suspend-resume-functionality.patch | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-pm/dss2/0065-VRFB-add-suspend-resume-functionality.patch b/recipes/linux/linux-omap-pm/dss2/0065-VRFB-add-suspend-resume-functionality.patch new file mode 100644 index 0000000000..17f959cb27 --- /dev/null +++ b/recipes/linux/linux-omap-pm/dss2/0065-VRFB-add-suspend-resume-functionality.patch @@ -0,0 +1,216 @@ +From 1269429fe6ddd6e5f15e3b4edb4fc2bcd6fc0410 Mon Sep 17 00:00:00 2001 +From: Imre Deak <imre.deak@nokia.com> +Date: Tue, 5 May 2009 11:16:13 +0200 +Subject: [PATCH 65/69] VRFB: add suspend/resume functionality + +At the moment the VRFB context is restored at each core power domain +OFF->ON transition. This is not optimal since the VRFB might be unused +temporarily for example when the screen is blanked. Add a suspend / +resume function to mark these unused periods during which we'll avoid +thea the context restore. + +Use atomic bitops for ctx_map for consistency. + +Signed-off-by: Imre Deak <imre.deak@nokia.com> +--- + arch/arm/plat-omap/include/mach/vrfb.h | 2 + + arch/arm/plat-omap/vrfb.c | 75 ++++++++++++++++++++++++----- + drivers/video/omap2/omapfb/omapfb-main.c | 28 +++++++++++ + 3 files changed, 92 insertions(+), 13 deletions(-) + +diff --git a/arch/arm/plat-omap/include/mach/vrfb.h b/arch/arm/plat-omap/include/mach/vrfb.h +index ee6c062..9647d82 100644 +--- a/arch/arm/plat-omap/include/mach/vrfb.h ++++ b/arch/arm/plat-omap/include/mach/vrfb.h +@@ -39,6 +39,8 @@ struct vrfb + + extern int omap_vrfb_request_ctx(struct vrfb *vrfb); + extern void omap_vrfb_release_ctx(struct vrfb *vrfb); ++extern void omap_vrfb_suspend_ctx(struct vrfb *vrfb); ++extern void omap_vrfb_resume_ctx(struct vrfb *vrfb); + extern void omap_vrfb_adjust_size(u16 *width, u16 *height, + u8 bytespp); + extern void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr, +diff --git a/arch/arm/plat-omap/vrfb.c b/arch/arm/plat-omap/vrfb.c +index 289fc8a..29f04e2 100644 +--- a/arch/arm/plat-omap/vrfb.c ++++ b/arch/arm/plat-omap/vrfb.c +@@ -1,7 +1,9 @@ + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/ioport.h> ++ + #include <asm/io.h> ++#include <asm/bitops.h> + + #include <mach/io.h> + #include <mach/vrfb.h> +@@ -37,7 +39,9 @@ + + #define VRFB_NUM_CTXS 12 + /* bitmap of reserved contexts */ +-static unsigned ctx_map; ++static unsigned long ctx_map; ++/* bitmap of contexts for which we have to keep the HW context valid */ ++static unsigned long ctx_map_active; + + /* + * Access to this happens from client drivers or the PM core after wake-up. +@@ -51,18 +55,23 @@ struct { + u32 size; + } vrfb_hw_context[VRFB_NUM_CTXS]; + ++static void inline restore_hw_context(int ctx) ++{ ++ omap_writel(vrfb_hw_context[ctx].control, SMS_ROT_CONTROL(ctx)); ++ omap_writel(vrfb_hw_context[ctx].size, SMS_ROT_SIZE(ctx)); ++ omap_writel(vrfb_hw_context[ctx].physical_ba, SMS_ROT_PHYSICAL_BA(ctx)); ++} ++ + void omap_vrfb_restore_context(void) + { + int i; ++ unsigned long map = ctx_map_active; + +- for (i = 0; i < VRFB_NUM_CTXS; i++) { +- /* Restore only the active contexts */ +- if (!(ctx_map & (1 << i))) +- continue; +- omap_writel(vrfb_hw_context[i].control, SMS_ROT_CONTROL(i)); +- omap_writel(vrfb_hw_context[i].size, SMS_ROT_SIZE(i)); +- omap_writel(vrfb_hw_context[i].physical_ba, +- SMS_ROT_PHYSICAL_BA(i)); ++ for (i = ffs(map); i; i = ffs(map)) { ++ /* i=1..32 */ ++ i--; ++ map &= ~(1 << i); ++ restore_hw_context(i); + } + } + +@@ -156,13 +165,20 @@ EXPORT_SYMBOL(omap_vrfb_setup); + void omap_vrfb_release_ctx(struct vrfb *vrfb) + { + int rot; ++ int ctx = vrfb->context; + +- if (vrfb->context == 0xff) ++ if (ctx == 0xff) + return; + +- DBG("release ctx %d\n", vrfb->context); ++ DBG("release ctx %d\n", ctx); + +- ctx_map &= ~(1 << vrfb->context); ++ if (!(ctx_map & (1 << ctx))) { ++ BUG(); ++ return; ++ } ++ WARN_ON(!(ctx_map_active & (1 << ctx))); ++ clear_bit(ctx, &ctx_map_active); ++ clear_bit(ctx, &ctx_map); + + for (rot = 0; rot < 4; ++rot) { + if(vrfb->paddr[rot]) { +@@ -194,7 +210,9 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb) + + DBG("found free ctx %d\n", ctx); + +- ctx_map |= 1 << ctx; ++ set_bit(ctx, &ctx_map); ++ WARN_ON(ctx_map_active & (1 << ctx)); ++ set_bit(ctx, &ctx_map_active); + + memset(vrfb, 0, sizeof(*vrfb)); + +@@ -219,3 +237,34 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb) + } + EXPORT_SYMBOL(omap_vrfb_request_ctx); + ++void omap_vrfb_suspend_ctx(struct vrfb *vrfb) ++{ ++ DBG("suspend ctx %d\n", vrfb->context); ++ if (vrfb->context >= VRFB_NUM_CTXS || ++ (!(1 << vrfb->context) & ctx_map_active)) { ++ BUG(); ++ return; ++ } ++ clear_bit(vrfb->context, &ctx_map_active); ++} ++EXPORT_SYMBOL(omap_vrfb_suspend_ctx); ++ ++void omap_vrfb_resume_ctx(struct vrfb *vrfb) ++{ ++ DBG("resume ctx %d\n", vrfb->context); ++ if (vrfb->context >= VRFB_NUM_CTXS || ++ ((1 << vrfb->context) & ctx_map_active)) { ++ BUG(); ++ return; ++ } ++ /* ++ * omap_vrfb_restore_context is normally called by the core domain ++ * save / restore logic, but since this VRFB context was suspended ++ * those calls didn't actually restore the context and now we might ++ * have an invalid context. Do an explicit restore here. ++ */ ++ restore_hw_context(vrfb->context); ++ set_bit(vrfb->context, &ctx_map_active); ++} ++EXPORT_SYMBOL(omap_vrfb_resume_ctx); ++ +diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c +index 76e7c6c..4bb74b7 100644 +--- a/drivers/video/omap2/omapfb/omapfb-main.c ++++ b/drivers/video/omap2/omapfb/omapfb-main.c +@@ -1036,6 +1036,30 @@ static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) + return 0; + } + ++static void omapfb_vrfb_suspend_all(struct omapfb2_device *fbdev) ++{ ++ int i; ++ ++ for (i = 0; i < fbdev->num_fbs; i++) { ++ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); ++ ++ if (ofbi->region.vrfb.vaddr[0]) ++ omap_vrfb_suspend_ctx(&ofbi->region.vrfb); ++ } ++} ++ ++static void omapfb_vrfb_resume_all(struct omapfb2_device *fbdev) ++{ ++ int i; ++ ++ for (i = 0; i < fbdev->num_fbs; i++) { ++ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); ++ ++ if (ofbi->region.vrfb.vaddr[0]) ++ omap_vrfb_resume_ctx(&ofbi->region.vrfb); ++ } ++} ++ + static int omapfb_blank(int blank, struct fb_info *fbi) + { + struct omapfb_info *ofbi = FB2OFB(fbi); +@@ -1051,6 +1075,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi) + if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) + goto exit; + ++ omapfb_vrfb_resume_all(fbdev); ++ + if (display->resume) + r = display->resume(display); + +@@ -1073,6 +1099,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi) + if (display->suspend) + r = display->suspend(display); + ++ omapfb_vrfb_suspend_all(fbdev); ++ + break; + + default: +-- +1.6.2.4 + |