From: Stanislav Vorobiov Date: Mon, 1 Jul 2013 11:52:59 +0000 (+0400) Subject: VIGS: Walk fb notifier call chain on DPMS X-Git-Tag: submit/tizen_common/20140905.094502~149 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1a3d88dc89859e240346a08c00c181025a73f1f7;p=sdk%2Femulator%2Femulator-kernel.git VIGS: Walk fb notifier call chain on DPMS Since currently maru_bl is used to control LCD power we need a way to trigger it. fbdev does this automatically on FB_BLANK events by walking fb notifier call chain. DRM doesn't do this on DPMS, so we need to do this ourselves Change-Id: I9585b06c027b210b4b563c2332c092a3084663e2 --- diff --git a/drivers/gpu/drm/vigs/vigs_crtc.c b/drivers/gpu/drm/vigs/vigs_crtc.c index 8c985d07132c..2ae8c04946de 100644 --- a/drivers/gpu/drm/vigs/vigs_crtc.c +++ b/drivers/gpu/drm/vigs/vigs_crtc.c @@ -3,18 +3,9 @@ #include "vigs_framebuffer.h" #include "vigs_surface.h" #include "vigs_comm.h" +#include "vigs_fbdev.h" #include "drm_crtc_helper.h" -struct vigs_crtc -{ - struct drm_crtc base; -}; - -static inline struct vigs_crtc *crtc_to_vigs_crtc(struct drm_crtc *crtc) -{ - return container_of(crtc, struct vigs_crtc, base); -} - static int vigs_crtc_update(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { @@ -74,7 +65,41 @@ static void vigs_crtc_destroy(struct drm_crtc *crtc) static void vigs_crtc_dpms(struct drm_crtc *crtc, int mode) { - DRM_DEBUG_KMS("enter: mode = %d\n", mode); + struct vigs_crtc *vigs_crtc = crtc_to_vigs_crtc(crtc); + struct vigs_device *vigs_dev = crtc->dev->dev_private; + int blank; + struct fb_event event; + + DRM_DEBUG_KMS("enter: fb_blank = %d, mode = %d\n", + vigs_crtc->in_fb_blank, + mode); + + if (vigs_crtc->in_fb_blank) { + return; + } + + switch (mode) { + case DRM_MODE_DPMS_ON: + blank = FB_BLANK_UNBLANK; + break; + case DRM_MODE_DPMS_STANDBY: + blank = FB_BLANK_NORMAL; + break; + case DRM_MODE_DPMS_SUSPEND: + blank = FB_BLANK_VSYNC_SUSPEND; + break; + case DRM_MODE_DPMS_OFF: + blank = FB_BLANK_POWERDOWN; + break; + default: + DRM_ERROR("unspecified mode %d\n", mode); + return; + } + + event.info = vigs_dev->fbdev->base.fbdev; + event.data = ␣ + + fb_notifier_call_chain(FB_EVENT_BLANK, &event); } static bool vigs_crtc_mode_fixup(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/vigs/vigs_crtc.h b/drivers/gpu/drm/vigs/vigs_crtc.h index ad9b0ce498ca..6f33feb0e813 100644 --- a/drivers/gpu/drm/vigs/vigs_crtc.h +++ b/drivers/gpu/drm/vigs/vigs_crtc.h @@ -5,6 +5,22 @@ struct vigs_device; +struct vigs_crtc +{ + struct drm_crtc base; + + /* + * A hack to tell if DPMS callback is called from inside + * 'fb_blank' or not. + */ + bool in_fb_blank; +}; + +static inline struct vigs_crtc *crtc_to_vigs_crtc(struct drm_crtc *crtc) +{ + return container_of(crtc, struct vigs_crtc, base); +} + int vigs_crtc_init(struct vigs_device *vigs_dev); #endif diff --git a/drivers/gpu/drm/vigs/vigs_fbdev.c b/drivers/gpu/drm/vigs/vigs_fbdev.c index 3ea71295bfd8..3b2a523d0e5c 100644 --- a/drivers/gpu/drm/vigs/vigs_fbdev.c +++ b/drivers/gpu/drm/vigs/vigs_fbdev.c @@ -3,6 +3,7 @@ #include "vigs_surface.h" #include "vigs_framebuffer.h" #include "vigs_output.h" +#include "vigs_crtc.h" #include "drm_crtc_helper.h" #include @@ -130,13 +131,87 @@ static int vigs_fbdev_setcmap(struct fb_cmap *cmap, struct fb_info *fbi) * @} */ -int vigs_fbdev_set_par(struct fb_info *fbi) +static int vigs_fbdev_set_par(struct fb_info *fbi) { DRM_DEBUG_KMS("enter\n"); return drm_fb_helper_set_par(fbi); } +/* + * This is 'drm_fb_helper_dpms' modified to set 'fbdev' + * flag inside 'mode_config.mutex'. + */ +static void vigs_fbdev_dpms(struct fb_info *fbi, int dpms_mode) +{ + struct drm_fb_helper *fb_helper = fbi->par; + struct drm_device *dev = fb_helper->dev; + struct drm_crtc *crtc; + struct vigs_crtc *vigs_crtc; + struct drm_connector *connector; + int i, j; + + /* + * For each CRTC in this fb, turn the connectors on/off. + */ + mutex_lock(&dev->mode_config.mutex); + + for (i = 0; i < fb_helper->crtc_count; i++) { + crtc = fb_helper->crtc_info[i].mode_set.crtc; + vigs_crtc = crtc_to_vigs_crtc(crtc); + + if (!crtc->enabled) { + continue; + } + + vigs_crtc->in_fb_blank = true; + + /* Walk the connectors & encoders on this fb turning them on/off */ + for (j = 0; j < fb_helper->connector_count; j++) { + connector = fb_helper->connector_info[j]->connector; + drm_helper_connector_dpms(connector, dpms_mode); + drm_connector_property_set_value(connector, + dev->mode_config.dpms_property, dpms_mode); + } + + vigs_crtc->in_fb_blank = false; + } + + mutex_unlock(&dev->mode_config.mutex); +} + +/* + * This is 'drm_fb_helper_blank' modified to use + * 'vigs_fbdev_dpms'. + */ +static int vigs_fbdev_blank(int blank, struct fb_info *fbi) +{ + switch (blank) { + /* Display: On; HSync: On, VSync: On */ + case FB_BLANK_UNBLANK: + vigs_fbdev_dpms(fbi, DRM_MODE_DPMS_ON); + break; + /* Display: Off; HSync: On, VSync: On */ + case FB_BLANK_NORMAL: + vigs_fbdev_dpms(fbi, DRM_MODE_DPMS_STANDBY); + break; + /* Display: Off; HSync: Off, VSync: On */ + case FB_BLANK_HSYNC_SUSPEND: + vigs_fbdev_dpms(fbi, DRM_MODE_DPMS_STANDBY); + break; + /* Display: Off; HSync: On, VSync: Off */ + case FB_BLANK_VSYNC_SUSPEND: + vigs_fbdev_dpms(fbi, DRM_MODE_DPMS_SUSPEND); + break; + /* Display: Off; HSync: Off, VSync: Off */ + case FB_BLANK_POWERDOWN: + vigs_fbdev_dpms(fbi, DRM_MODE_DPMS_OFF); + break; + } + + return 0; +} + static struct fb_ops vigs_fbdev_ops = { .owner = THIS_MODULE, @@ -145,7 +220,7 @@ static struct fb_ops vigs_fbdev_ops = .fb_imageblit = cfb_imageblit, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = vigs_fbdev_set_par, - .fb_blank = drm_fb_helper_blank, + .fb_blank = vigs_fbdev_blank, .fb_pan_display = drm_fb_helper_pan_display, .fb_setcmap = vigs_fbdev_setcmap, .fb_debug_enter = drm_fb_helper_debug_enter,