From c26aa6e5aab9d145b343a2a71243508378e59621 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 5 May 2009 11:16:13 +0200 Subject: [PATCH 063/146] 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 --- 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 #include #include + #include +#include #include #include @@ -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