diff options
author | Zhao Yakui <yakui.zhao@intel.com> | 2009-06-22 01:17:08 -0400 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2009-07-15 02:29:33 -0400 |
commit | d782c3f95c9263dc0b98e7115f75f1e18b9600b3 (patch) | |
tree | e58d950cfa9b9a3a0c52e0f91a08b00cb2be8421 | |
parent | e9e961c9a818a2f24711af493b907a8e40a69efc (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.c | 219 | ||||
-rw-r--r-- | 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 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) | |||
62 | EXPORT_SYMBOL(drm_mode_debug_printmodeline); | 63 | EXPORT_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 | ||
89 | struct 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 | } | ||
281 | EXPORT_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, | |||
736 | extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, | 736 | extern 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); |
738 | extern bool drm_detect_hdmi_monitor(struct edid *edid); | 738 | extern bool drm_detect_hdmi_monitor(struct edid *edid); |
739 | extern 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__ */ |