File: gtf.c

package info (click to toggle)
libdisplay-info 0.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,156 kB
  • sloc: ansic: 8,413; python: 294; sh: 131; makefile: 3
file content (129 lines) | stat: -rw-r--r-- 4,581 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Copyright 2006-2012 Red Hat, Inc.
 * Copyright 2018-2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
 *
 * Originally imported from edid-decode.
 */

#include <math.h>

#include <libdisplay-info/gtf.h>

/**
 * The assumed character cell granularity of the graphics system, in pixels.
 */
#define CELL_GRAN 8.0
/**
 * The size of the top and bottom overscan margin as a percentage of the active
 * vertical image.
 */
#define MARGIN_PERC 1.8
/**
 * The minimum front porch in lines (vertical) and character cells (horizontal).
 */
#define MIN_PORCH 1.0
/**
 * The width of the V sync in lines.
 */
#define V_SYNC_RQD 3.0
/**
 * The width of the H sync as a percentage of the total line period.
 */
#define H_SYNC_PERC 8.0
/**
 * Minimum time of vertical sync + back porch interval (µs).
 */
#define MIN_VSYNC_BP 550.0

void di_gtf_compute(struct di_gtf_timing *t, const struct di_gtf_options *options)
{
	double c_prime, m_prime, h_pixels_rnd, v_lines_rnd, h_margin,
	       v_margin, interlace, total_active_pixels, pixel_freq,
	       h_blank_pixels, total_pixels, v_sync_bp, v_field_rate_rqd,
	       h_period_est, total_v_lines, v_field_rate_est, h_period,
	       ideal_duty_cycle, h_freq, ideal_h_period, v_back_porch, h_sync,
	       h_front_porch;

	/* C' and M' are part of the Blanking Duty Cycle computation */
	c_prime = ((options->c - options->j) * options->k / 256.0) + options->j;
	m_prime = options->k / 256.0 * options->m;

	h_pixels_rnd = round(options->h_pixels / CELL_GRAN) * CELL_GRAN;
	v_lines_rnd = options->int_rqd ?
		      round(options->v_lines / 2.0) :
		      options->v_lines;
	h_margin = options->margins_rqd ?
		   round(h_pixels_rnd * MARGIN_PERC / 100.0 / CELL_GRAN) * CELL_GRAN :
		   0;
	v_margin = options->margins_rqd ?
		   round(MARGIN_PERC / 100.0 * v_lines_rnd) :
		   0;
	interlace = options->int_rqd ? 0.5 : 0;
	total_active_pixels = h_pixels_rnd + h_margin * 2;

	switch (options->ip_param) {
	case DI_GTF_IP_PARAM_V_FRAME_RATE:
		// vertical frame frequency (Hz)
		v_field_rate_rqd = options->int_rqd ?
				   options->ip_freq_rqd * 2 :
				   options->ip_freq_rqd;
		h_period_est = (1.0 / v_field_rate_rqd - MIN_VSYNC_BP / 1000000.0) /
			       (v_lines_rnd + v_margin * 2 + MIN_PORCH + interlace) * 1000000.0;
		v_sync_bp = round(MIN_VSYNC_BP / h_period_est);
		total_v_lines = v_lines_rnd + v_margin * 2 +
				v_sync_bp + interlace + MIN_PORCH;
		v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
		h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
		ideal_duty_cycle = c_prime - m_prime * h_period / 1000.0;
		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
				       (100.0 - ideal_duty_cycle) /
				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
		total_pixels = total_active_pixels + h_blank_pixels;
		pixel_freq = total_pixels / h_period;
		break;
	case DI_GTF_IP_PARAM_H_FREQ:
		// horizontal frequency (kHz)
		h_freq = options->ip_freq_rqd;
		v_sync_bp = round(MIN_VSYNC_BP * h_freq / 1000.0);
		ideal_duty_cycle = c_prime - m_prime / h_freq;
		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
				       (100.0 - ideal_duty_cycle) /
				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
		total_pixels = total_active_pixels + h_blank_pixels;
		pixel_freq = total_pixels * h_freq / 1000.0;
		break;
	case DI_GTF_IP_PARAM_H_PIXELS:
		// pixel clock rate (MHz)
		pixel_freq = options->ip_freq_rqd;
		ideal_h_period = (c_prime - 100.0 +
				  sqrt((100.0 - c_prime) * (100.0 - c_prime) +
				       0.4 * m_prime * (total_active_pixels + h_margin * 2) / pixel_freq))
				  / 2.0 / m_prime * 1000.0;
		ideal_duty_cycle = c_prime - m_prime * ideal_h_period / 1000.0;
		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
				       (100.0 - ideal_duty_cycle) /
				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
		total_pixels = total_active_pixels + h_blank_pixels;
		h_freq = pixel_freq / total_pixels * 1000.0;
		v_sync_bp = round(MIN_VSYNC_BP * h_freq / 1000.0);
		break;
	}

	v_back_porch = v_sync_bp - V_SYNC_RQD;
	h_sync = round(H_SYNC_PERC / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
	h_front_porch = h_blank_pixels / 2.0 - h_sync;

	*t = (struct di_gtf_timing) {
		.h_pixels = (int) h_pixels_rnd,
		.v_lines = options->v_lines,
		.v_sync = V_SYNC_RQD,
		.h_sync = (int) h_sync,
		.v_front_porch = MIN_PORCH,
		.v_back_porch = (int) v_back_porch,
		.h_front_porch = (int) h_front_porch,
		.h_back_porch = (int) (h_front_porch + h_sync),
		.h_border = (int) h_margin,
		.v_border = (int) v_margin,
		.pixel_freq_mhz = pixel_freq,
	};
}