Skip to content

Commit

Permalink
drm/mode: add the CVT algorithm in kernel space
Browse files Browse the repository at this point in the history
Add the CVT algorithm in kernel space. And this function can be called to
generate the required modeline.

I copied 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.

[airlied:- cleaned up some bits]
Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
  • Loading branch information
Zhao Yakui authored and Dave Airlie committed Jul 15, 2009
1 parent e9e961c commit d782c3f
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 0 deletions.
219 changes: 219 additions & 0 deletions drivers/gpu/drm/drm_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Copyright © 2007 Dave Airlie
* Copyright © 2007-2008 Intel Corporation
* Jesse Barnes <jesse.barnes@intel.com>
* 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"),
Expand Down Expand Up @@ -61,6 +62,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
* @vrefresh : vrefresh 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, vdisplay, vrefresh.
* 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 vrefresh,
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;
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
*/
drm_mode = drm_mode_create(dev);
if (!drm_mode)
return NULL;

/* the CVT default refresh rate is 60Hz */
if (!vrefresh)
vrefresh = 60;

/* the required field fresh rate */
if (interlaced)
vfieldrate = vrefresh * 2;
else
vfieldrate = vrefresh;

/* 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
Expand Down
3 changes: 3 additions & 0 deletions include/drm/drm_crtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 vrefresh,
bool reduced, bool interlaced);
#endif /* __DRM_CRTC_H__ */

0 comments on commit d782c3f

Please sign in to comment.