aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhao Yakui <yakui.zhao@intel.com>2009-06-22 01:17:08 -0400
committerDave Airlie <airlied@linux.ie>2009-07-15 02:29:33 -0400
commitd782c3f95c9263dc0b98e7115f75f1e18b9600b3 (patch)
treee58d950cfa9b9a3a0c52e0f91a08b00cb2be8421
parente9e961c9a818a2f24711af493b907a8e40a69efc (diff)
drm/mode: add the CVT algorithm in kernel space
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>
-rw-r--r--drivers/gpu/drm/drm_modes.c219
-rw-r--r--include/drm/drm_crtc.h3
2 files changed, 222 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 54f492a488a9..0dbc7e4f8643 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -8,6 +8,7 @@
8 * Copyright © 2007 Dave Airlie 8 * Copyright © 2007 Dave Airlie
9 * Copyright © 2007-2008 Intel Corporation 9 * Copyright © 2007-2008 Intel Corporation
10 * Jesse Barnes <jesse.barnes@intel.com> 10 * Jesse Barnes <jesse.barnes@intel.com>
11 * Copyright 2005-2006 Luc Verhaegen
11 * 12 *
12 * Permission is hereby granted, free of charge, to any person obtaining a 13 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"), 14 * copy of this software and associated documentation files (the "Software"),
@@ -62,6 +63,224 @@ void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
62EXPORT_SYMBOL(drm_mode_debug_printmodeline); 63EXPORT_SYMBOL(drm_mode_debug_printmodeline);
63 64
64/** 65/**
66 * drm_cvt_mode -create a modeline based on CVT algorithm
67 * @dev: DRM device
68 * @hdisplay: hdisplay size
69 * @vdisplay: vdisplay size
70 * @vrefresh : vrefresh rate
71 * @reduced : Whether the GTF calculation is simplified
72 * @interlaced:Whether the interlace is supported
73 *
74 * LOCKING:
75 * none.
76 *
77 * return the modeline based on CVT algorithm
78 *
79 * This function is called to generate the modeline based on CVT algorithm
80 * according to the hdisplay, vdisplay, vrefresh.
81 * It is based from the VESA(TM) Coordinated Video Timing Generator by
82 * Graham Loveridge April 9, 2003 available at
83 * http://www.vesa.org/public/CVT/CVTd6r1.xls
84 *
85 * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
86 * What I have done is to translate it by using integer calculation.
87 */
88#define HV_FACTOR 1000
89struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
90 int vdisplay, int vrefresh,
91 bool reduced, bool interlaced)
92{
93 /* 1) top/bottom margin size (% of height) - default: 1.8, */
94#define CVT_MARGIN_PERCENTAGE 18
95 /* 2) character cell horizontal granularity (pixels) - default 8 */
96#define CVT_H_GRANULARITY 8
97 /* 3) Minimum vertical porch (lines) - default 3 */
98#define CVT_MIN_V_PORCH 3
99 /* 4) Minimum number of vertical back porch lines - default 6 */
100#define CVT_MIN_V_BPORCH 6
101 /* Pixel Clock step (kHz) */
102#define CVT_CLOCK_STEP 250
103 struct drm_display_mode *drm_mode;
104 bool margins = false;
105 unsigned int vfieldrate, hperiod;
106 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
107 int interlace;
108
109 /* allocate the drm_display_mode structure. If failure, we will
110 * return directly
111 */
112 drm_mode = drm_mode_create(dev);
113 if (!drm_mode)
114 return NULL;
115
116 /* the CVT default refresh rate is 60Hz */
117 if (!vrefresh)
118 vrefresh = 60;
119
120 /* the required field fresh rate */
121 if (interlaced)
122 vfieldrate = vrefresh * 2;
123 else
124 vfieldrate = vrefresh;
125
126 /* horizontal pixels */
127 hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
128
129 /* determine the left&right borders */
130 hmargin = 0;
131 if (margins) {
132 hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
133 hmargin -= hmargin % CVT_H_GRANULARITY;
134 }
135 /* find the total active pixels */
136 drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
137
138 /* find the number of lines per field */
139 if (interlaced)
140 vdisplay_rnd = vdisplay / 2;
141 else
142 vdisplay_rnd = vdisplay;
143
144 /* find the top & bottom borders */
145 vmargin = 0;
146 if (margins)
147 vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
148
149 drm_mode->vdisplay = vdisplay_rnd + 2 * vmargin;
150
151 /* Interlaced */
152 if (interlaced)
153 interlace = 1;
154 else
155 interlace = 0;
156
157 /* Determine VSync Width from aspect ratio */
158 if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
159 vsync = 4;
160 else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
161 vsync = 5;
162 else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
163 vsync = 6;
164 else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
165 vsync = 7;
166 else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
167 vsync = 7;
168 else /* custom */
169 vsync = 10;
170
171 if (!reduced) {
172 /* simplify the GTF calculation */
173 /* 4) Minimum time of vertical sync + back porch interval (µs)
174 * default 550.0
175 */
176 int tmp1, tmp2;
177#define CVT_MIN_VSYNC_BP 550
178 /* 3) Nominal HSync width (% of line period) - default 8 */
179#define CVT_HSYNC_PERCENTAGE 8
180 unsigned int hblank_percentage;
181 int vsyncandback_porch, vback_porch, hblank;
182
183 /* estimated the horizontal period */
184 tmp1 = HV_FACTOR * 1000000 -
185 CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
186 tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
187 interlace;
188 hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
189
190 tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
191 /* 9. Find number of lines in sync + backporch */
192 if (tmp1 < (vsync + CVT_MIN_V_PORCH))
193 vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
194 else
195 vsyncandback_porch = tmp1;
196 /* 10. Find number of lines in back porch */
197 vback_porch = vsyncandback_porch - vsync;
198 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
199 vsyncandback_porch + CVT_MIN_V_PORCH;
200 /* 5) Definition of Horizontal blanking time limitation */
201 /* Gradient (%/kHz) - default 600 */
202#define CVT_M_FACTOR 600
203 /* Offset (%) - default 40 */
204#define CVT_C_FACTOR 40
205 /* Blanking time scaling factor - default 128 */
206#define CVT_K_FACTOR 128
207 /* Scaling factor weighting - default 20 */
208#define CVT_J_FACTOR 20
209#define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256)
210#define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
211 CVT_J_FACTOR)
212 /* 12. Find ideal blanking duty cycle from formula */
213 hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
214 hperiod / 1000;
215 /* 13. Blanking time */
216 if (hblank_percentage < 20 * HV_FACTOR)
217 hblank_percentage = 20 * HV_FACTOR;
218 hblank = drm_mode->hdisplay * hblank_percentage /
219 (100 * HV_FACTOR - hblank_percentage);
220 hblank -= hblank % (2 * CVT_H_GRANULARITY);
221 /* 14. find the total pixes per line */
222 drm_mode->htotal = drm_mode->hdisplay + hblank;
223 drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
224 drm_mode->hsync_start = drm_mode->hsync_end -
225 (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
226 drm_mode->hsync_start += CVT_H_GRANULARITY -
227 drm_mode->hsync_start % CVT_H_GRANULARITY;
228 /* fill the Vsync values */
229 drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
230 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
231 } else {
232 /* Reduced blanking */
233 /* Minimum vertical blanking interval time (µs)- default 460 */
234#define CVT_RB_MIN_VBLANK 460
235 /* Fixed number of clocks for horizontal sync */
236#define CVT_RB_H_SYNC 32
237 /* Fixed number of clocks for horizontal blanking */
238#define CVT_RB_H_BLANK 160
239 /* Fixed number of lines for vertical front porch - default 3*/
240#define CVT_RB_VFPORCH 3
241 int vbilines;
242 int tmp1, tmp2;
243 /* 8. Estimate Horizontal period. */
244 tmp1 = HV_FACTOR * 1000000 -
245 CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
246 tmp2 = vdisplay_rnd + 2 * vmargin;
247 hperiod = tmp1 / (tmp2 * vfieldrate);
248 /* 9. Find number of lines in vertical blanking */
249 vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
250 /* 10. Check if vertical blanking is sufficient */
251 if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
252 vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
253 /* 11. Find total number of lines in vertical field */
254 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
255 /* 12. Find total number of pixels in a line */
256 drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
257 /* Fill in HSync values */
258 drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
259 drm_mode->hsync_start = drm_mode->hsync_end = CVT_RB_H_SYNC;
260 }
261 /* 15/13. Find pixel clock frequency (kHz for xf86) */
262 drm_mode->clock = drm_mode->htotal * HV_FACTOR * 1000 / hperiod;
263 drm_mode->clock -= drm_mode->clock % CVT_CLOCK_STEP;
264 /* 18/16. Find actual vertical frame frequency */
265 /* ignore - just set the mode flag for interlaced */
266 if (interlaced)
267 drm_mode->vtotal *= 2;
268 /* Fill the mode line name */
269 drm_mode_set_name(drm_mode);
270 if (reduced)
271 drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
272 DRM_MODE_FLAG_NVSYNC);
273 else
274 drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
275 DRM_MODE_FLAG_NHSYNC);
276 if (interlaced)
277 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
278
279 return drm_mode;
280}
281EXPORT_SYMBOL(drm_cvt_mode);
282
283/**
65 * drm_mode_set_name - set the name on a mode 284 * drm_mode_set_name - set the name on a mode
66 * @mode: name will be set in this mode 285 * @mode: name will be set in this mode
67 * 286 *
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 7300fb866767..820bc0977e5e 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,
736extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, 736extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
737 void *data, struct drm_file *file_priv); 737 void *data, struct drm_file *file_priv);
738extern bool drm_detect_hdmi_monitor(struct edid *edid); 738extern bool drm_detect_hdmi_monitor(struct edid *edid);
739extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
740 int hdisplay, int vdisplay, int vrefresh,
741 bool reduced, bool interlaced);
739#endif /* __DRM_CRTC_H__ */ 742#endif /* __DRM_CRTC_H__ */