From patchwork Wed Jul 22 08:56:43 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Zhao, Yakui" X-Patchwork-Id: 36727 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n6M8tZLm012165 for ; Wed, 22 Jul 2009 08:55:35 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 75A269E7F4; Wed, 22 Jul 2009 01:55:35 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by gabe.freedesktop.org (Postfix) with ESMTP id E5D7E9E7F4 for ; Wed, 22 Jul 2009 01:55:33 -0700 (PDT) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga101.fm.intel.com with ESMTP; 22 Jul 2009 01:54:45 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.43,245,1246863600"; d="scan'208";a="476975574" Received: from yakui_zhao.sh.intel.com (HELO localhost.localdomain) ([10.239.13.79]) by fmsmga002.fm.intel.com with ESMTP; 22 Jul 2009 01:48:46 -0700 From: yakui.zhao@intel.com To: airlied@redhat.com Date: Wed, 22 Jul 2009 16:56:43 +0800 Message-Id: <1248253005-10337-1-git-send-email-yakui.zhao@intel.com> X-Mailer: git-send-email 1.5.4.5 Cc: intel-gfx@lists.freedesktop.org, dri-devel@sourceforege.net Subject: [Intel-gfx] [PATCH 1/3] DRM: Add the CVT algorithm in kernel space X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Mime-version: 1.0 Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org From: Zhao Yakui Add the CVT algorithm in kernel space. And this function can be called to generate the required modeline. I copy it from the file of xserver/hw/xfree86/modes/xf86cvt.c. What I have done is to translate it by using integer calculation. This is to avoid the float-point calculation in kernel space. Signed-off-by: Zhao Yakui --- drivers/gpu/drm/drm_modes.c | 219 +++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 3 + 2 files changed, 222 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 54f492a..50325e9 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -8,6 +8,7 @@ * Copyright © 2007 Dave Airlie * Copyright © 2007-2008 Intel Corporation * Jesse Barnes + * Copyright 2005-2006 Luc Verhaegen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -62,6 +63,224 @@ void drm_mode_debug_printmodeline(struct drm_display_mode *mode) EXPORT_SYMBOL(drm_mode_debug_printmodeline); /** + * drm_cvt_mode -create a modeline based on CVT algorithm + * @dev: DRM device + * @hdisplay: hdisplay size + * @vdisplay: vdisplay size + * @vfresh : vfresh rate + * @reduced : Whether the GTF calculation is simplified + * @interlaced:Whether the interlace is supported + * + * LOCKING: + * none. + * + * return the modeline based on CVT algorithm + * + * This function is called to generate the modeline based on CVT algorithm + * according to the hdisplay, vdispaly, vfresh. + * It is based from the VESA(TM) Coordinated Video Timing Generator by + * Graham Loveridge April 9, 2003 available at + * http://www.vesa.org/public/CVT/CVTd6r1.xls + * + * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c. + * What I have done is to translate it by using integer calculation. + */ +#define HV_FACTOR 1000 +struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, + int vdisplay, int vfresh, + bool reduced, bool interlaced) +{ + /* 1) top/bottom margin size (% of height) - default: 1.8, */ +#define CVT_MARGIN_PERCENTAGE 18 + /* 2) character cell horizontal granularity (pixels) - default 8 */ +#define CVT_H_GRANULARITY 8 + /* 3) Minimum vertical porch (lines) - default 3 */ +#define CVT_MIN_V_PORCH 3 + /* 4) Minimum number of vertical back porch lines - default 6 */ +#define CVT_MIN_V_BPORCH 6 + /* Pixel Clock step (kHz) */ +#define CVT_CLOCK_STEP 250 + struct drm_display_mode *drm_mode = NULL; + bool margins = false; + unsigned int vfieldrate, hperiod; + int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync; + int interlace; + + /* allocate the drm_display_mode structure. If failure, we will + * return directly + */ + if (dev) + drm_mode = drm_mode_create(dev); + + if (!drm_mode) + return NULL; + /* the CVT default fresh rate is 60Hz */ + if (!vfresh) + vfresh = 60; + + /* the required field fresh rate */ + if (interlaced) + vfieldrate = vfresh * 2; + else + vfieldrate = vfresh; + + /* horizontal pixels */ + hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY); + + /* determine the left&right borders */ + hmargin = 0; + if (margins) { + hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000; + hmargin -= hmargin % CVT_H_GRANULARITY; + } + /* find the total active pixels */ + drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin; + + /* find the number of lines per field */ + if (interlaced) + vdisplay_rnd = vdisplay / 2; + else + vdisplay_rnd = vdisplay; + + /* find the top & bottom borders */ + vmargin = 0; + if (margins) + vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000; + + drm_mode->vdisplay = vdisplay_rnd + 2 * vmargin; + + /* Interlaced */ + if (interlaced) + interlace = 1; + else + interlace = 0; + + /* Determine VSync Width from aspect ratio */ + if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay)) + vsync = 4; + else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay)) + vsync = 5; + else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay)) + vsync = 6; + else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay)) + vsync = 7; + else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay)) + vsync = 7; + else /* custom */ + vsync = 10; + + if (!reduced) { + /* simplify the GTF calculation */ + /* 4) Minimum time of vertical sync + back porch interval (µs) + * default 550.0 + */ + int tmp1, tmp2; +#define CVT_MIN_VSYNC_BP 550 + /* 3) Nominal HSync width (% of line period) - default 8 */ +#define CVT_HSYNC_PERCENTAGE 8 + unsigned int hblank_percentage; + int vsyncandback_porch, vback_porch, hblank; + + /* estimated the horizontal period */ + tmp1 = HV_FACTOR * 1000000 - + CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate; + tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 + + interlace; + hperiod = tmp1 * 2 / (tmp2 * vfieldrate); + + tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1; + /* 9. Find number of lines in sync + backporch */ + if (tmp1 < (vsync + CVT_MIN_V_PORCH)) + vsyncandback_porch = vsync + CVT_MIN_V_PORCH; + else + vsyncandback_porch = tmp1; + /* 10. Find number of lines in back porch */ + vback_porch = vsyncandback_porch - vsync; + drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + + vsyncandback_porch + CVT_MIN_V_PORCH; + /* 5) Definition of Horizontal blanking time limitation */ + /* Gradient (%/kHz) - default 600 */ +#define CVT_M_FACTOR 600 + /* Offset (%) - default 40 */ +#define CVT_C_FACTOR 40 + /* Blanking time scaling factor - default 128 */ +#define CVT_K_FACTOR 128 + /* Scaling factor weighting - default 20 */ +#define CVT_J_FACTOR 20 +#define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256) +#define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \ + CVT_J_FACTOR) + /* 12. Find ideal blanking duty cycle from formula */ + hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME * + hperiod / 1000; + /* 13. Blanking time */ + if (hblank_percentage < 20 * HV_FACTOR) + hblank_percentage = 20 * HV_FACTOR; + hblank = drm_mode->hdisplay * hblank_percentage / + (100 * HV_FACTOR - hblank_percentage); + hblank -= hblank % (2 * CVT_H_GRANULARITY); + /* 14. find the total pixes per line */ + drm_mode->htotal = drm_mode->hdisplay + hblank; + drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2; + drm_mode->hsync_start = drm_mode->hsync_end - + (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100; + drm_mode->hsync_start += CVT_H_GRANULARITY - + drm_mode->hsync_start % CVT_H_GRANULARITY; + /* fill the Vsync values */ + drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH; + drm_mode->vsync_end = drm_mode->vsync_start + vsync; + } else { + /* Reduced blanking */ + /* Minimum vertical blanking interval time (µs)- default 460 */ +#define CVT_RB_MIN_VBLANK 460 + /* Fixed number of clocks for horizontal sync */ +#define CVT_RB_H_SYNC 32 + /* Fixed number of clocks for horizontal blanking */ +#define CVT_RB_H_BLANK 160 + /* Fixed number of lines for vertical front porch - default 3*/ +#define CVT_RB_VFPORCH 3 + int vbilines; + int tmp1, tmp2; + /* 8. Estimate Horizontal period. */ + tmp1 = HV_FACTOR * 1000000 - + CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate; + tmp2 = vdisplay_rnd + 2 * vmargin; + hperiod = tmp1 / (tmp2 * vfieldrate); + /* 9. Find number of lines in vertical blanking */ + vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1; + /* 10. Check if vertical blanking is sufficient */ + if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH)) + vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH; + /* 11. Find total number of lines in vertical field */ + drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines; + /* 12. Find total number of pixels in a line */ + drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK; + /* Fill in HSync values */ + drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2; + drm_mode->hsync_start = drm_mode->hsync_end = CVT_RB_H_SYNC; + } + /* 15/13. Find pixel clock frequency (kHz for xf86) */ + drm_mode->clock = drm_mode->htotal * HV_FACTOR * 1000 / hperiod; + drm_mode->clock -= drm_mode->clock % CVT_CLOCK_STEP; + /* 18/16. Find actual vertical frame frequency */ + /* ignore - just set the mode flag for interlaced */ + if (interlaced) + drm_mode->vtotal *= 2; + /* Fill the mode line name */ + drm_mode_set_name(drm_mode); + if (reduced) + drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC | + DRM_MODE_FLAG_NVSYNC); + else + drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_NHSYNC); + if (interlaced) + drm_mode->flags |= DRM_MODE_FLAG_INTERLACE; + + return drm_mode; +} +EXPORT_SYMBOL(drm_cvt_mode); +/** * drm_mode_set_name - set the name on a mode * @mode: name will be set in this mode * diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7300fb8..a00ba2c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -736,4 +736,7 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern bool drm_detect_hdmi_monitor(struct edid *edid); +extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, + int hdisplay, int vdisplay, int vfresh, + bool reduced, bool interlaced); #endif /* __DRM_CRTC_H__ */