diff options
author | Zhao Yakui <yakui.zhao@intel.com> | 2009-06-22 01:17:09 -0400 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2009-07-15 02:31:43 -0400 |
commit | 26bbdadad356ec02d33657858d91675f3e9aca94 (patch) | |
tree | 12fe6960ac50e03d1b1cd7f352ec5e86abbe11ec /drivers/gpu/drm | |
parent | d782c3f95c9263dc0b98e7115f75f1e18b9600b3 (diff) |
drm/mode: add the GTF algorithm in kernel space
Add the GTF 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/xf86gtf.c. What I have
done is to translate it by using integer calculation. This is to avoid
the float-point calculation in kernel space.
At the same tie I also refer to the function of fb_get_mode in
drivers/video/fbmon.c
Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/drm_modes.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 0dbc7e4f8643..fd489d76fbbc 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c | |||
@@ -9,6 +9,7 @@ | |||
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 | * Copyright 2005-2006 Luc Verhaegen |
12 | * Copyright (c) 2001, Andy Ritger aritger@nvidia.com | ||
12 | * | 13 | * |
13 | * Permission is hereby granted, free of charge, to any person obtaining a | 14 | * Permission is hereby granted, free of charge, to any person obtaining a |
14 | * copy of this software and associated documentation files (the "Software"), | 15 | * copy of this software and associated documentation files (the "Software"), |
@@ -281,6 +282,202 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, | |||
281 | EXPORT_SYMBOL(drm_cvt_mode); | 282 | EXPORT_SYMBOL(drm_cvt_mode); |
282 | 283 | ||
283 | /** | 284 | /** |
285 | * drm_gtf_mode - create the modeline based on GTF algorithm | ||
286 | * | ||
287 | * @dev :drm device | ||
288 | * @hdisplay :hdisplay size | ||
289 | * @vdisplay :vdisplay size | ||
290 | * @vrefresh :vrefresh rate. | ||
291 | * @interlaced :whether the interlace is supported | ||
292 | * @margins :whether the margin is supported | ||
293 | * | ||
294 | * LOCKING. | ||
295 | * none. | ||
296 | * | ||
297 | * return the modeline based on GTF algorithm | ||
298 | * | ||
299 | * This function is to create the modeline based on the GTF algorithm. | ||
300 | * Generalized Timing Formula is derived from: | ||
301 | * GTF Spreadsheet by Andy Morrish (1/5/97) | ||
302 | * available at http://www.vesa.org | ||
303 | * | ||
304 | * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c. | ||
305 | * What I have done is to translate it by using integer calculation. | ||
306 | * I also refer to the function of fb_get_mode in the file of | ||
307 | * drivers/video/fbmon.c | ||
308 | */ | ||
309 | struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay, | ||
310 | int vdisplay, int vrefresh, | ||
311 | bool interlaced, int margins) | ||
312 | { | ||
313 | /* 1) top/bottom margin size (% of height) - default: 1.8, */ | ||
314 | #define GTF_MARGIN_PERCENTAGE 18 | ||
315 | /* 2) character cell horizontal granularity (pixels) - default 8 */ | ||
316 | #define GTF_CELL_GRAN 8 | ||
317 | /* 3) Minimum vertical porch (lines) - default 3 */ | ||
318 | #define GTF_MIN_V_PORCH 1 | ||
319 | /* width of vsync in lines */ | ||
320 | #define V_SYNC_RQD 3 | ||
321 | /* width of hsync as % of total line */ | ||
322 | #define H_SYNC_PERCENT 8 | ||
323 | /* min time of vsync + back porch (microsec) */ | ||
324 | #define MIN_VSYNC_PLUS_BP 550 | ||
325 | /* blanking formula gradient */ | ||
326 | #define GTF_M 600 | ||
327 | /* blanking formula offset */ | ||
328 | #define GTF_C 40 | ||
329 | /* blanking formula scaling factor */ | ||
330 | #define GTF_K 128 | ||
331 | /* blanking formula scaling factor */ | ||
332 | #define GTF_J 20 | ||
333 | /* C' and M' are part of the Blanking Duty Cycle computation */ | ||
334 | #define GTF_C_PRIME (((GTF_C - GTF_J) * GTF_K / 256) + GTF_J) | ||
335 | #define GTF_M_PRIME (GTF_K * GTF_M / 256) | ||
336 | struct drm_display_mode *drm_mode; | ||
337 | unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd; | ||
338 | int top_margin, bottom_margin; | ||
339 | int interlace; | ||
340 | unsigned int hfreq_est; | ||
341 | int vsync_plus_bp, vback_porch; | ||
342 | unsigned int vtotal_lines, vfieldrate_est, hperiod; | ||
343 | unsigned int vfield_rate, vframe_rate; | ||
344 | int left_margin, right_margin; | ||
345 | unsigned int total_active_pixels, ideal_duty_cycle; | ||
346 | unsigned int hblank, total_pixels, pixel_freq; | ||
347 | int hsync, hfront_porch, vodd_front_porch_lines; | ||
348 | unsigned int tmp1, tmp2; | ||
349 | |||
350 | drm_mode = drm_mode_create(dev); | ||
351 | if (!drm_mode) | ||
352 | return NULL; | ||
353 | |||
354 | /* 1. In order to give correct results, the number of horizontal | ||
355 | * pixels requested is first processed to ensure that it is divisible | ||
356 | * by the character size, by rounding it to the nearest character | ||
357 | * cell boundary: | ||
358 | */ | ||
359 | hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN; | ||
360 | hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN; | ||
361 | |||
362 | /* 2. If interlace is requested, the number of vertical lines assumed | ||
363 | * by the calculation must be halved, as the computation calculates | ||
364 | * the number of vertical lines per field. | ||
365 | */ | ||
366 | if (interlaced) | ||
367 | vdisplay_rnd = vdisplay / 2; | ||
368 | else | ||
369 | vdisplay_rnd = vdisplay; | ||
370 | |||
371 | /* 3. Find the frame rate required: */ | ||
372 | if (interlaced) | ||
373 | vfieldrate_rqd = vrefresh * 2; | ||
374 | else | ||
375 | vfieldrate_rqd = vrefresh; | ||
376 | |||
377 | /* 4. Find number of lines in Top margin: */ | ||
378 | top_margin = 0; | ||
379 | if (margins) | ||
380 | top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) / | ||
381 | 1000; | ||
382 | /* 5. Find number of lines in bottom margin: */ | ||
383 | bottom_margin = top_margin; | ||
384 | |||
385 | /* 6. If interlace is required, then set variable interlace: */ | ||
386 | if (interlaced) | ||
387 | interlace = 1; | ||
388 | else | ||
389 | interlace = 0; | ||
390 | |||
391 | /* 7. Estimate the Horizontal frequency */ | ||
392 | { | ||
393 | tmp1 = (1000000 - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500; | ||
394 | tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) * | ||
395 | 2 + interlace; | ||
396 | hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1; | ||
397 | } | ||
398 | |||
399 | /* 8. Find the number of lines in V sync + back porch */ | ||
400 | /* [V SYNC+BP] = RINT(([MIN VSYNC+BP] * hfreq_est / 1000000)) */ | ||
401 | vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000; | ||
402 | vsync_plus_bp = (vsync_plus_bp + 500) / 1000; | ||
403 | /* 9. Find the number of lines in V back porch alone: */ | ||
404 | vback_porch = vsync_plus_bp - V_SYNC_RQD; | ||
405 | /* 10. Find the total number of lines in Vertical field period: */ | ||
406 | vtotal_lines = vdisplay_rnd + top_margin + bottom_margin + | ||
407 | vsync_plus_bp + GTF_MIN_V_PORCH; | ||
408 | /* 11. Estimate the Vertical field frequency: */ | ||
409 | vfieldrate_est = hfreq_est / vtotal_lines; | ||
410 | /* 12. Find the actual horizontal period: */ | ||
411 | hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines); | ||
412 | |||
413 | /* 13. Find the actual Vertical field frequency: */ | ||
414 | vfield_rate = hfreq_est / vtotal_lines; | ||
415 | /* 14. Find the Vertical frame frequency: */ | ||
416 | if (interlaced) | ||
417 | vframe_rate = vfield_rate / 2; | ||
418 | else | ||
419 | vframe_rate = vfield_rate; | ||
420 | /* 15. Find number of pixels in left margin: */ | ||
421 | if (margins) | ||
422 | left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) / | ||
423 | 1000; | ||
424 | else | ||
425 | left_margin = 0; | ||
426 | |||
427 | /* 16.Find number of pixels in right margin: */ | ||
428 | right_margin = left_margin; | ||
429 | /* 17.Find total number of active pixels in image and left and right */ | ||
430 | total_active_pixels = hdisplay_rnd + left_margin + right_margin; | ||
431 | /* 18.Find the ideal blanking duty cycle from blanking duty cycle */ | ||
432 | ideal_duty_cycle = GTF_C_PRIME * 1000 - | ||
433 | (GTF_M_PRIME * 1000000 / hfreq_est); | ||
434 | /* 19.Find the number of pixels in the blanking time to the nearest | ||
435 | * double character cell: */ | ||
436 | hblank = total_active_pixels * ideal_duty_cycle / | ||
437 | (100000 - ideal_duty_cycle); | ||
438 | hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN); | ||
439 | hblank = hblank * 2 * GTF_CELL_GRAN; | ||
440 | /* 20.Find total number of pixels: */ | ||
441 | total_pixels = total_active_pixels + hblank; | ||
442 | /* 21.Find pixel clock frequency: */ | ||
443 | pixel_freq = total_pixels * hfreq_est / 1000; | ||
444 | /* Stage 1 computations are now complete; I should really pass | ||
445 | * the results to another function and do the Stage 2 computations, | ||
446 | * but I only need a few more values so I'll just append the | ||
447 | * computations here for now */ | ||
448 | /* 17. Find the number of pixels in the horizontal sync period: */ | ||
449 | hsync = H_SYNC_PERCENT * total_pixels / 100; | ||
450 | hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN; | ||
451 | hsync = hsync * GTF_CELL_GRAN; | ||
452 | /* 18. Find the number of pixels in horizontal front porch period */ | ||
453 | hfront_porch = hblank / 2 - hsync; | ||
454 | /* 36. Find the number of lines in the odd front porch period: */ | ||
455 | vodd_front_porch_lines = GTF_MIN_V_PORCH ; | ||
456 | |||
457 | /* finally, pack the results in the mode struct */ | ||
458 | drm_mode->hdisplay = hdisplay_rnd; | ||
459 | drm_mode->hsync_start = hdisplay_rnd + hfront_porch; | ||
460 | drm_mode->hsync_end = drm_mode->hsync_start + hsync; | ||
461 | drm_mode->htotal = total_pixels; | ||
462 | drm_mode->vdisplay = vdisplay_rnd; | ||
463 | drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines; | ||
464 | drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD; | ||
465 | drm_mode->vtotal = vtotal_lines; | ||
466 | |||
467 | drm_mode->clock = pixel_freq; | ||
468 | |||
469 | drm_mode_set_name(drm_mode); | ||
470 | drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC; | ||
471 | |||
472 | if (interlaced) { | ||
473 | drm_mode->vtotal *= 2; | ||
474 | drm_mode->flags |= DRM_MODE_FLAG_INTERLACE; | ||
475 | } | ||
476 | |||
477 | return drm_mode; | ||
478 | } | ||
479 | EXPORT_SYMBOL(drm_gtf_mode); | ||
480 | /** | ||
284 | * drm_mode_set_name - set the name on a mode | 481 | * drm_mode_set_name - set the name on a mode |
285 | * @mode: name will be set in this mode | 482 | * @mode: name will be set in this mode |
286 | * | 483 | * |