• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006-2012 Red Hat, Inc.
3  * Copyright 2018-2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4  *
5  * Originally imported from edid-decode.
6  */
7 
8 #include <math.h>
9 
10 #include <libdisplay-info/gtf.h>
11 
12 /**
13  * The assumed character cell granularity of the graphics system, in pixels.
14  */
15 #define CELL_GRAN 8.0
16 /**
17  * The size of the top and bottom overscan margin as a percentage of the active
18  * vertical image.
19  */
20 #define MARGIN_PERC 1.8
21 /**
22  * The minimum front porch in lines (vertical) and character cells (horizontal).
23  */
24 #define MIN_PORCH 1.0
25 /**
26  * The width of the V sync in lines.
27  */
28 #define V_SYNC_RQD 3.0
29 /**
30  * The width of the H sync as a percentage of the total line period.
31  */
32 #define H_SYNC_PERC 8.0
33 /**
34  * Minimum time of vertical sync + back porch interval (µs).
35  */
36 #define MIN_VSYNC_BP 550.0
37 
di_gtf_compute(struct di_gtf_timing * t,const struct di_gtf_options * options)38 void di_gtf_compute(struct di_gtf_timing *t, const struct di_gtf_options *options)
39 {
40 	double c_prime, m_prime, h_pixels_rnd, v_lines_rnd, h_margin,
41 	       v_margin, interlace, total_active_pixels, pixel_freq,
42 	       h_blank_pixels, total_pixels, v_sync_bp, v_field_rate_rqd,
43 	       h_period_est, total_v_lines, v_field_rate_est, h_period,
44 	       ideal_duty_cycle, h_freq, ideal_h_period, v_back_porch, h_sync,
45 	       h_front_porch;
46 
47 	/* C' and M' are part of the Blanking Duty Cycle computation */
48 	c_prime = ((options->c - options->j) * options->k / 256.0) + options->j;
49 	m_prime = options->k / 256.0 * options->m;
50 
51 	h_pixels_rnd = round(options->h_pixels / CELL_GRAN) * CELL_GRAN;
52 	v_lines_rnd = options->int_rqd ?
53 		      round(options->v_lines / 2.0) :
54 		      options->v_lines;
55 	h_margin = options->margins_rqd ?
56 		   round(h_pixels_rnd * MARGIN_PERC / 100.0 / CELL_GRAN) * CELL_GRAN :
57 		   0;
58 	v_margin = options->margins_rqd ?
59 		   round(MARGIN_PERC / 100.0 * v_lines_rnd) :
60 		   0;
61 	interlace = options->int_rqd ? 0.5 : 0;
62 	total_active_pixels = h_pixels_rnd + h_margin * 2;
63 
64 	switch (options->ip_param) {
65 	case DI_GTF_IP_PARAM_V_FRAME_RATE:
66 		// vertical frame frequency (Hz)
67 		v_field_rate_rqd = options->int_rqd ?
68 				   options->ip_freq_rqd * 2 :
69 				   options->ip_freq_rqd;
70 		h_period_est = (1.0 / v_field_rate_rqd - MIN_VSYNC_BP / 1000000.0) /
71 			       (v_lines_rnd + v_margin * 2 + MIN_PORCH + interlace) * 1000000.0;
72 		v_sync_bp = round(MIN_VSYNC_BP / h_period_est);
73 		total_v_lines = v_lines_rnd + v_margin * 2 +
74 				v_sync_bp + interlace + MIN_PORCH;
75 		v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
76 		h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
77 		ideal_duty_cycle = c_prime - m_prime * h_period / 1000.0;
78 		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
79 				       (100.0 - ideal_duty_cycle) /
80 				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
81 		total_pixels = total_active_pixels + h_blank_pixels;
82 		pixel_freq = total_pixels / h_period;
83 		break;
84 	case DI_GTF_IP_PARAM_H_FREQ:
85 		// horizontal frequency (kHz)
86 		h_freq = options->ip_freq_rqd;
87 		v_sync_bp = round(MIN_VSYNC_BP * h_freq / 1000.0);
88 		ideal_duty_cycle = c_prime - m_prime / h_freq;
89 		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
90 				       (100.0 - ideal_duty_cycle) /
91 				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
92 		total_pixels = total_active_pixels + h_blank_pixels;
93 		pixel_freq = total_pixels * h_freq / 1000.0;
94 		break;
95 	case DI_GTF_IP_PARAM_H_PIXELS:
96 		// pixel clock rate (MHz)
97 		pixel_freq = options->ip_freq_rqd;
98 		ideal_h_period = (c_prime - 100.0 +
99 				  sqrt((100.0 - c_prime) * (100.0 - c_prime) +
100 				       0.4 * m_prime * (total_active_pixels + h_margin * 2) / pixel_freq))
101 				  / 2.0 / m_prime * 1000.0;
102 		ideal_duty_cycle = c_prime - m_prime * ideal_h_period / 1000.0;
103 		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
104 				       (100.0 - ideal_duty_cycle) /
105 				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
106 		total_pixels = total_active_pixels + h_blank_pixels;
107 		h_freq = pixel_freq / total_pixels * 1000.0;
108 		v_sync_bp = round(MIN_VSYNC_BP * h_freq / 1000.0);
109 		break;
110 	}
111 
112 	v_back_porch = v_sync_bp - V_SYNC_RQD;
113 	h_sync = round(H_SYNC_PERC / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
114 	h_front_porch = h_blank_pixels / 2.0 - h_sync;
115 
116 	*t = (struct di_gtf_timing) {
117 		.h_pixels = (int) h_pixels_rnd,
118 		.v_lines = options->v_lines,
119 		.v_sync = V_SYNC_RQD,
120 		.h_sync = (int) h_sync,
121 		.v_front_porch = MIN_PORCH,
122 		.v_back_porch = (int) v_back_porch,
123 		.h_front_porch = (int) h_front_porch,
124 		.h_back_porch = (int) (h_front_porch + h_sync),
125 		.h_border = (int) h_margin,
126 		.v_border = (int) v_margin,
127 		.pixel_freq_mhz = pixel_freq,
128 	};
129 }
130