From 1f1b2e2c408f7cb9b111a4d8a2a24bc245a23f9d Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 17 Jun 2020 11:13:35 +0200 Subject: Add CVT files --- src/cvt.c | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cvt.h | 26 +++ 2 files changed, 578 insertions(+) create mode 100644 src/cvt.c create mode 100644 src/cvt.h diff --git a/src/cvt.c b/src/cvt.c new file mode 100644 index 0000000..9563f0f --- /dev/null +++ b/src/cvt.c @@ -0,0 +1,552 @@ +#include "cvt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Based on the cvt util: + * http://www.uruk.org/projects/cvt/cvt.c + */ + +#include +#include +#include + +#define CLOCK_STEP 0.25 /* Clock steps in MHz */ +#define MARGIN_PERCENT 1.8 /* % of active vertical image */ +#define H_SYNC_PER 8.0 /* sync % of horizontal image */ +#define CELL_GRAN 8.4999 /* assumed character cell granularity */ +#define CELL_GRAN_RND 8.0 /* assumed character cell granularity (round)*/ +#define MIN_V_BPORCH 3.0 /* width of vsync in lines */ +#define MIN_V_PORCH_RND 3.0 /* width of vsync in lines */ +#define M 600.0 /* blanking formula gradient */ +#define C 40.0 /* blanking formula offset */ +#define K 128.0 /* blanking formula scaling factor */ +#define J 20.0 /* blanking formula scaling factor */ + +/* Standard Timing Parameters */ +#define MIN_VSYNC_BP 550.0 /* min time of vsync + back porch (us) */ +#define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */ + +/* Reduced Blanking defines */ +#define RB_MIN_V_BPORCH 6.0 /* lines */ +#define RB_V_FPORCH 3.0 /* lines */ +#define RB_MIN_V_BLANK 460.0 /* us */ +#define RB_H_SYNC 32.0 /* pixels */ +#define RB_H_BLANK 160.0 /* pixels */ + +/* C' and M' are part of the Blanking Duty Cycle computation */ + +#define C_PRIME (((C - J) * K/256.0) + J) +#define M_PRIME (K/256.0 * M) + +/* NOP out prints */ +#define print_value(...) (void)0 + +typedef struct __options +{ + int x, y; + int reduced_blank, interlaced; + int xf86mode, fbmode; + float v_freq; +} options; + + +/* + * vert_refresh() - as defined by the CVT Timing Standard, compute the + * Stage 1 Parameters using the vertical refresh frequency. In other + * words: input a desired resolution and desired refresh rate, and + * output the CVT mode timings. + * + * XXX margin computations are implemented but not tested (nor used by + * XFree86 of fbset mode descriptions, from what I can tell). + */ + +mode *vert_refresh (int h_pixels, int v_lines, float freq, + int interlaced, int reduced_blank, int margins) +{ + float h_pixels_rnd; + float v_lines_rnd; + float v_field_rate_rqd; + float top_margin; + float bot_margin; + float interlace; + float h_period_est; + float v_sync_bp; + float total_v_lines; + float left_margin; + float right_margin; + float total_active_pixels; + float ideal_duty_cycle; + float h_blank; + float total_pixels; + + float cur_duty_cycle; + float v_sync; + float v_sync_rnd, h_sync_rnd; + float h_back_porch, v_front_porch, h_front_porch; + + float vbi_lines, act_vbi_lines, rb_min_vbi; + float act_pixel_freq, act_h_freq; + float act_field_rate, act_frame_rate; + char *aspect_ratio; + int stage; + + mode *m = (mode*) malloc (sizeof (mode)); + + + /* 1. Required Field Rate + * + * This is slightly different from the spreadsheet because we use + * a different result for interlaced video modes. Simplifies this + * to the input field rate. + * + * [V FIELD RATE RQD] = [I/P FREQ RQD] + */ + + v_field_rate_rqd = freq; + + print_value(1, "[V FIELD RATE RQD]", v_field_rate_rqd); + + + /* 2. Horizontal Pixels + * + * In order to give correct results, the number of horizontal + * pixels requested is first processed to ensure that it is divisible + * by the character size, by rounding it to the nearest character + * cell boundary. + * + * [H PIXELS RND] = ((ROUNDDOWN([H PIXELS]/[CELL GRAN RND],0)) + * *[CELLGRAN RND]) + */ + + h_pixels_rnd = floor((float) h_pixels / CELL_GRAN_RND) * CELL_GRAN_RND; + + print_value(2, "[H PIXELS RND]", h_pixels_rnd); + + + /* 2.5th Calculation, aspect_ratio & v_sync_rnd + * + * [ASPECT_RATIO] = IF(H_PIXELS_RND = CELL_GRAN_RND*ROUND((V_LINES* + * 4.0/3.0)/CELL_GRAN_RND),"4:3") + * etc... + * [V_SYNC] = [value from table based on aspect ratio] + * [V_SYNC_RND] = ROUND(V_SYNC,0) // Not needed in principle + */ + + if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 4.0 / 3.0) + / CELL_GRAN_RND)) { + aspect_ratio = "4:3"; + v_sync = 4; + } else if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 16.0 + / 9.0) / CELL_GRAN_RND)) { + aspect_ratio = "16:9"; + v_sync = 5; + } else if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 16.0 + / 10.0) / CELL_GRAN_RND)) { + aspect_ratio = "16:10"; + v_sync = 6; + } else if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 5.0 + / 4.0) / CELL_GRAN_RND)) { + aspect_ratio = "5:4"; + v_sync = 7; + } else if (h_pixels_rnd == CELL_GRAN_RND * floor(((float)v_lines * 15.0 + / 9.0) / CELL_GRAN_RND)) { + aspect_ratio = "15:9"; + v_sync = 7; + } else { + /* Default case of unknown aspect ratio */ + aspect_ratio = "Custom"; + v_sync = 10; + } + v_sync_rnd = v_sync; + + /* + * 3. Determine Left & Right Borders + * + * Calculate the margins on the left and right side. + * + * [LEFT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", + * (ROUNDDOWN( ([H PIXELS RND] * [MARGIN%] / 100 / + * [CELL GRAN RND]),0)) * [CELL GRAN RND], + * 0)) + * [RIGHT MARGIN (PIXELS)] = (IF( [MARGINS RQD?]="Y", + * (ROUNDDOWN( ([H PIXELS RND] * [MARGIN%] / 100 / + * [CELL GRAN RND]),0)) * [CELL GRAN RND], + * 0)) + */ + + left_margin = margins ? + floor(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN_RND) + * CELL_GRAN_RND : 0.0; + right_margin = left_margin; + + print_value(3, "[LEFT MARGIN (PIXELS)]", left_margin); + print_value(3, "[RIGHT MARGIN (PIXELS)]", right_margin); + + + /* 4. Find total active pixels. + * + * Find total number of active pixels in image and left and right + * margins. + * + * [TOTAL ACTIVE PIXELS] = [H PIXELS RND] + [LEFT MARGIN (PIXELS)] + + * [RIGHT MARGIN (PIXELS)] + */ + + total_active_pixels = h_pixels_rnd + left_margin + right_margin; + + print_value(4, "[TOTAL ACTIVE PIXELS]", total_active_pixels); + + + /* 5. Find number of lines per field. + * + * If interlace is requested, the number of vertical lines assumed + * by the calculation must be halved, as the computation calculates + * the number of vertical lines per field. In either case, the + * number of lines is rounded to the nearest integer. + * + * [V LINES RND] = IF([INT RQD?]="y", ROUNDDOWN([V LINES]/2,0), + * ROUNDDOWN([V LINES],0)) + */ + + v_lines_rnd = interlaced ? + floor((float) v_lines / 2.0) : + floor((float) v_lines); + + print_value(5, "[V LINES RND]", v_lines_rnd); + + + /* 6. Find Top and Bottom margins. + * + * [TOP MARGIN (LINES)] = IF([MARGINS RQD?]="Y", + * ROUNDDOWN(([MARGIN%]/100*[V LINES RND]),0), + * 0) + * [BOT MARGIN (LINES)] = IF([MARGINS RQD?]="Y", + * ROUNDDOWN(([MARGIN%]/100*[V LINES RND]),0), + * 0) + */ + + top_margin = margins ? floor(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0); + bot_margin = top_margin; + + print_value(6, "[TOP MARGIN (LINES)]", top_margin); + print_value(6, "[BOT MARGIN (LINES)]", bot_margin); + + + /* 7. If interlace is required, then set variable [INTERLACE]=0.5: + * + * [INTERLACE]=(IF([INT RQD?]="y",0.5,0)) + */ + + interlace = interlaced ? 0.5 : 0.0; + + print_value(7, "[INTERLACE]", interlace); + + + /* + * Here it diverges for "reduced blanking" or normal blanking modes. + */ + + if (reduced_blank) { + h_blank = RB_H_BLANK; + + + /* 8. Estimate Horiz. Period (us). + * + * [H PERIOD EST] = ((1000000/V_FIELD_RATE_RQD)-RB_MIN_V_BLANK)/(V_LINES_RND+TOP_MARGIN+BOT_MARGIN) + */ + + h_period_est = (1000000.0/v_field_rate_rqd - RB_MIN_V_BLANK) + / (v_lines_rnd + top_margin + bot_margin); + + print_value(8, "[H PERIOD EST]", h_period_est); + + + /* 9. Find number of lines in vertical blanking. + * + * [Actual VBI_LINES] = RB_MIN_V_BLANK/H_PERIOD_EST + * [VBI_LINES] = ROUNDDOWN(RB_MIN_V_BLANK/H_PERIOD_EST,0) + 1 + */ + + vbi_lines = RB_MIN_V_BLANK/h_period_est; + print_value(9, "[Actual VBI LINES]", vbi_lines); + + vbi_lines = floor(vbi_lines) + 1.0; + print_value(9, "[VBI LINES]", vbi_lines); + + + /* 10. Check Vertical Blanking is sufficient. + * + * [RB MIN VBI] = RB_V_FPORCH+V_SYNC_RND+RB_MIN_V_BPORCH + * [ACT VBI LINES] = IF(VBI_LINEShr = (int) (h_pixels_rnd); + m->hss = (int) (h_pixels_rnd + h_front_porch); + m->hse = (int) (h_pixels_rnd + h_front_porch + h_sync_rnd); + m->hfl = (int) (total_pixels); + +#if 0 + m->vr = (int) (v_lines_rnd); + m->vss = (int) (v_lines_rnd + v_front_porch); + m->vse = (int) (v_lines_rnd + v_front_porch + v_sync_rnd); + m->vfl = (int) (total_v_lines); +#else + { + int real_v_lines = v_lines; + m->vr = (int) (real_v_lines); + m->vss = (int) (real_v_lines + v_front_porch); + m->vse = (int) (real_v_lines + v_front_porch + v_sync_rnd); + m->vfl = (int) (total_v_lines - v_lines_rnd + real_v_lines); + } +#endif + + m->pclk = act_pixel_freq; + m->h_freq = act_h_freq; + m->v_freq = freq; + m->real_v_rate = act_field_rate; + + m->in = interlaced; + m->rb = reduced_blank; + + return (m); + +} // vert_refresh() + +#ifdef __cplusplus +} +#endif diff --git a/src/cvt.h b/src/cvt.h new file mode 100644 index 0000000..7f2ce74 --- /dev/null +++ b/src/cvt.h @@ -0,0 +1,26 @@ +#ifndef __CVT_H_ +#define __CVT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* struct definitions */ + +typedef struct __mode +{ + int hr, hss, hse, hfl; + int vr, vss, vse, vfl; + float pclk, h_freq, v_freq; + float real_v_rate; + int rb, in; +} mode; + +mode *vert_refresh (int h_pixels, int v_lines, float freq, + int interlaced, int reduced_blank, int margins); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3-55-g7522