mirror of
https://github.com/marqs85/ossc
synced 2025-04-09 22:56:34 +03:00
update video mode selection and processing
Updated mode detection to be based on new TVP7002 frontend, and integrated Pure-LM functionality and processing from OSSC Pro.
This commit is contained in:
parent
86c3f744ed
commit
0839e118ad
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (C) 2015-2022 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
// Copyright (C) 2015-2023 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
//
|
||||
// This file is part of Open Source Scan Converter project.
|
||||
//
|
||||
@ -33,7 +33,6 @@
|
||||
#include "sdcard.h"
|
||||
#include "menu.h"
|
||||
#include "avconfig.h"
|
||||
#include "sysconfig.h"
|
||||
#include "firmware.h"
|
||||
#include "userdata.h"
|
||||
#include "it6613.h"
|
||||
@ -43,12 +42,9 @@
|
||||
#include "sd_io.h"
|
||||
#include "sys/alt_timestamp.h"
|
||||
|
||||
#define STABLE_THOLD 1
|
||||
#define MIN_LINES_PROGRESSIVE 200
|
||||
#define MIN_LINES_INTERLACED 400
|
||||
#define SYNC_LOCK_THOLD 3
|
||||
#define SYNC_LOSS_THOLD -5
|
||||
#define STATUS_TIMEOUT 100000
|
||||
#define STATUS_TIMEOUT_US 25000
|
||||
|
||||
#define PCNT_TOLERANCE 50
|
||||
|
||||
@ -57,7 +53,7 @@ alt_u32 sys_ctrl;
|
||||
// Current mode
|
||||
avmode_t cm;
|
||||
|
||||
extern mode_data_t video_modes[];
|
||||
extern mode_data_t video_modes_plm[];
|
||||
extern ypbpr_to_rgb_csc_t csc_coeffs[];
|
||||
extern alt_u16 rc_keymap[REMOTE_MAX_KEYS];
|
||||
extern alt_u16 rc_keymap_default[REMOTE_MAX_KEYS];
|
||||
@ -66,11 +62,11 @@ extern alt_u32 btn_code, btn_code_prev;
|
||||
extern alt_u8 remote_rpt, remote_rpt_prev;
|
||||
extern avconfig_t tc, tc_default;
|
||||
extern alt_u8 vm_sel;
|
||||
extern char target_profile_name[PROFILE_NAME_LEN+1];
|
||||
|
||||
tvp_input_t target_tvp;
|
||||
tvp_sync_input_t target_tvp_sync;
|
||||
alt_u8 target_type;
|
||||
alt_u8 stable_frames;
|
||||
alt_u8 update_cur_vm;
|
||||
|
||||
alt_u8 profile_sel, profile_sel_menu, input_profiles[AV_LAST], lt_sel, def_input, profile_link, lcd_bl_timeout;
|
||||
@ -84,9 +80,13 @@ avinput_t target_input;
|
||||
|
||||
alt_u8 pcm1862_active;
|
||||
|
||||
alt_u32 pclk_out;
|
||||
uint8_t sl_def_iv_x, sl_def_iv_y;
|
||||
|
||||
alt_u32 read_it2(alt_u32 regaddr);
|
||||
|
||||
mode_data_t vmode_in, vmode_out;
|
||||
vm_proc_config_t vm_conf;
|
||||
|
||||
// Manually (see cyiv-51005.pdf) or automatically (MIF/HEX from PLL megafunction) generated config may not
|
||||
// provide fully correct scan chain data (e.g. mismatches in C3) and lead to incorrect PLL configuration.
|
||||
// To get correct scan chain data, do the following:
|
||||
@ -100,9 +100,12 @@ alt_u32 read_it2(alt_u32 regaddr);
|
||||
// 8. Compare your MIF/HEX to the captured scan chain and update it accordingly
|
||||
// 9. Dump the updated scan chain data to an array like below (last 16 bits are 0)
|
||||
// 10. PLL can be then reconfigured with custom pll_reconfig as shown in program_mode()
|
||||
const pll_config_t pll_configs[] = { {{0x0d806000, 0x00402010, 0x08040220, 0x00004022, 0x00000000}}, // 1x, 1x (default)
|
||||
{{0x0dc06000, 0x00783c11, 0x070180e0, 0x0000180e, 0x00000000}}, // 2x, 5x
|
||||
{{0x0d806000, 0x00301804, 0x02014060, 0x00001406, 0x00000000}} }; // 3x, 4x
|
||||
const pll_config_t pll_configs[] = { {{0x0d806000, 0x00402010, 0x08800020, 0x00080002, 0x00000000}}, // 1x (default)
|
||||
{{0x0d806000, 0x00402008, 0x04800020, 0x00080002, 0x00000000}}, // 2x (~20-40MHz)
|
||||
{{0x0d806000, 0x00441c07, 0x02800020, 0x00080002, 0x00000000}}, // 3x (~20-40MHz)
|
||||
{{0x0d806000, 0x00402004, 0x02800020, 0x00080002, 0x00000000}}, // 4x (~20-40MHz)
|
||||
{{0x0d806000, 0x00441c05, 0x01800020, 0x00080002, 0x00000000}}, // 5x (~20-40MHz)
|
||||
{{0x0e406000, 0x00281407, 0x02800020, 0x00080002, 0x00000000}} }; // 2x (~75MHz)
|
||||
|
||||
volatile sc_regs *sc = (volatile sc_regs*)SC_CONFIG_0_BASE;
|
||||
volatile osd_regs *osd = (volatile osd_regs*)OSD_GENERATOR_0_BASE;
|
||||
@ -150,7 +153,7 @@ inline void SetupAudio(tx_mode_t mode)
|
||||
EnableAudioInfoFrame(FALSE, NULL);
|
||||
|
||||
if (mode != TX_DVI) {
|
||||
EnableAudioOutput4OSSC(pclk_out, tc.audio_dw_sampl, tc.audio_swap_lr);
|
||||
EnableAudioOutput4OSSC(cm.pclk_o_hz, tc.audio_dw_sampl, tc.audio_swap_lr);
|
||||
HDMITX_SetAudioInfoFrame((BYTE)tc.audio_dw_sampl);
|
||||
#ifdef DEBUG
|
||||
Switch_HDMITX_Bank(1);
|
||||
@ -177,7 +180,7 @@ inline void TX_enable(tx_mode_t mode)
|
||||
EnableVideoOutput(cm.hdmitx_pclk_level ? PCLK_HIGH : PCLK_MEDIUM, COLOR_RGB444, (mode == TX_HDMI_YCBCR444) ? COLOR_YUV444 : COLOR_RGB444, (mode != TX_DVI));
|
||||
|
||||
if (mode != TX_DVI) {
|
||||
HDMITX_SetAVIInfoFrame(cm.hdmitx_vic, (mode == TX_HDMI_RGB) ? F_MODE_RGB444 : F_MODE_YUV444, 0, 0, tc.hdmi_itc, cm.hdmitx_pixr_ifr);
|
||||
HDMITX_SetAVIInfoFrame(vmode_out.vic, (mode == TX_HDMI_RGB) ? F_MODE_RGB444 : F_MODE_YUV444, 0, 0, tc.hdmi_itc, cm.hdmitx_pixr_ifr);
|
||||
cm.cc.hdmi_itc = tc.hdmi_itc;
|
||||
}
|
||||
|
||||
@ -227,8 +230,7 @@ void pll_reconfigure(alt_u8 id)
|
||||
void set_lpf(alt_u8 lpf)
|
||||
{
|
||||
alt_u32 pclk;
|
||||
pclk = (TVP_EXTCLK_HZ/cm.clkcnt)*video_modes[cm.id].h_total;
|
||||
printf("PCLK_in: %luHz\n", pclk);
|
||||
pclk = estimate_dotclk(&vmode_in, (TVP_EXTCLK_HZ/cm.clkcnt));
|
||||
|
||||
//Auto
|
||||
if (lpf == 0) {
|
||||
@ -247,7 +249,6 @@ void set_lpf(alt_u8 lpf)
|
||||
ths_set_lpf(THS_LPF_16MHZ);
|
||||
break;
|
||||
case VIDEO_SDTV:
|
||||
case VIDEO_LDTV:
|
||||
default:
|
||||
ths_set_lpf(THS_LPF_9MHZ);
|
||||
break;
|
||||
@ -283,102 +284,69 @@ inline int check_linecnt(alt_u8 progressive, alt_u32 totlines) {
|
||||
return (totlines >= MIN_LINES_INTERLACED);
|
||||
}
|
||||
|
||||
void set_sampler_phase(uint8_t sampler_phase) {
|
||||
uint32_t sample_rng_x1000;
|
||||
uint8_t tvp_phase;
|
||||
|
||||
vmode_in.sampler_phase = sampler_phase;
|
||||
|
||||
if (vm_conf.h_skip == 0) {
|
||||
vm_conf.h_sample_sel = 0;
|
||||
tvp_phase = sampler_phase;
|
||||
} else {
|
||||
sample_rng_x1000 = 360000 / (vm_conf.h_skip+1);
|
||||
vm_conf.h_sample_sel = (sampler_phase*11250)/sample_rng_x1000;
|
||||
tvp_phase = ((((sampler_phase*11250) % sample_rng_x1000)*32)/sample_rng_x1000);
|
||||
}
|
||||
|
||||
if (vm_conf.h_skip > 0)
|
||||
printf("Sample sel: %u/%u\n", (vm_conf.h_sample_sel+1), (vm_conf.h_skip+1));
|
||||
|
||||
tvp_set_hpll_phase(tvp_phase);
|
||||
}
|
||||
|
||||
// Check if input video status / target configuration has changed
|
||||
status_t get_status(tvp_sync_input_t syncinput)
|
||||
{
|
||||
alt_u32 data1, data2;
|
||||
alt_u32 totlines, clkcnt, pcnt_frame;
|
||||
alt_u8 progressive;
|
||||
//alt_u8 refclk;
|
||||
alt_u8 sync_active;
|
||||
alt_u8 vsyncmode;
|
||||
alt_u16 totlines_tvp;
|
||||
alt_u16 h_samplerate;
|
||||
status_t status;
|
||||
static alt_8 act_ctr;
|
||||
alt_u32 ctr;
|
||||
int valid_linecnt;
|
||||
alt_u8 h_mult;
|
||||
|
||||
status = NO_CHANGE;
|
||||
alt_u8 progressive, sync_active, valid_linecnt;
|
||||
status_t status = NO_CHANGE;
|
||||
alt_timestamp_type start_ts = alt_timestamp();
|
||||
|
||||
// Wait until vsync active (avoid noise coupled to I2C bus on earlier prototypes)
|
||||
for (ctr=0; ctr<STATUS_TIMEOUT; ctr++) {
|
||||
if (sc->sc_status.vsync_flag) {
|
||||
//printf("ctrval %u\n", ctr);
|
||||
while (alt_timestamp() < start_ts + STATUS_TIMEOUT_US*(TIMER_0_FREQ/1000000)) {
|
||||
if (IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & VSYNC_FLAG_MASK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sync_active = tvp_check_sync(syncinput);
|
||||
vsyncmode = cm.sync_active ? sc->sc_status.fpga_vsyncgen : 0;
|
||||
//sync_active = tvp_check_sync(syncinput);
|
||||
sync_active = sc->fe_status.sync_active;
|
||||
|
||||
// Read sync information from TVP7002 status registers
|
||||
data1 = tvp_readreg(TVP_LINECNT1);
|
||||
data2 = tvp_readreg(TVP_LINECNT2);
|
||||
/*totlines = ((data2 & 0x0f) << 8) | data1;
|
||||
progressive = !!(data2 & (1<<5));*/
|
||||
totlines = sc->sc_status.vmax;
|
||||
progressive = !sc->sc_status.interlace_flag;
|
||||
cm.macrovis = !!(data2 & (1<<6));
|
||||
data1 = tvp_readreg(TVP_CLKCNT1);
|
||||
data2 = tvp_readreg(TVP_CLKCNT2);
|
||||
//clkcnt = ((data2 & 0x0f) << 8) | data1;
|
||||
pcnt_frame = (unsigned long)sc->sc_status2.pcnt_frame;
|
||||
// Read sync information from TVP7002 frontend
|
||||
totlines = sc->fe_status.vtotal;
|
||||
progressive = !sc->fe_status.interlace_flag;
|
||||
pcnt_frame = (unsigned long)sc->fe_status2.pcnt_frame;
|
||||
clkcnt = pcnt_frame/(totlines>>!progressive);
|
||||
|
||||
// Read how many lines TVP7002 outputs in reality (valid only if output enabled)
|
||||
/*totlines_tvp = sc->sc_status.vmax_tvp+1;
|
||||
valid_linecnt = check_linecnt(progressive, totlines);
|
||||
|
||||
// NOTE: "progressive" may not have correct value if H-PLL is not locked (!cm.sync_active)
|
||||
if ((vsyncmode == 0x2) || (!cm.sync_active && (totlines < MIN_LINES_INTERLACED))) {
|
||||
progressive = 1;
|
||||
} else if (vsyncmode == 0x1) {
|
||||
progressive = 0;
|
||||
totlines = totlines_tvp; //compensate skipped vsync
|
||||
}*/
|
||||
|
||||
//valid_linecnt = check_linecnt(progressive, totlines);
|
||||
valid_linecnt = 1;
|
||||
|
||||
// TVP7002 may randomly report "no sync" (especially with arcade boards),
|
||||
// thus disable output only after N consecutive "no sync"-events
|
||||
// Check sync activity
|
||||
if (!cm.sync_active && sync_active && valid_linecnt) {
|
||||
printf("Sync up in %d...\n", SYNC_LOCK_THOLD-act_ctr);
|
||||
if (act_ctr >= SYNC_LOCK_THOLD) {
|
||||
act_ctr = 0;
|
||||
cm.sync_active = 1;
|
||||
status = ACTIVITY_CHANGE;
|
||||
} else {
|
||||
act_ctr++;
|
||||
}
|
||||
cm.sync_active = 1;
|
||||
status = ACTIVITY_CHANGE;
|
||||
} else if (cm.sync_active && (!sync_active || !valid_linecnt)) {
|
||||
printf("Sync down in %d...\n", act_ctr-SYNC_LOSS_THOLD);
|
||||
if (act_ctr <= SYNC_LOSS_THOLD) {
|
||||
act_ctr = 0;
|
||||
cm.sync_active = 0;
|
||||
status = ACTIVITY_CHANGE;
|
||||
} else {
|
||||
act_ctr--;
|
||||
}
|
||||
} else {
|
||||
act_ctr = 0;
|
||||
cm.sync_active = 0;
|
||||
status = ACTIVITY_CHANGE;
|
||||
}
|
||||
|
||||
if (valid_linecnt) {
|
||||
// Line count reported in TVP7002 status registers is sometimes +-1 line off and may alternate with correct value. Ignore these events
|
||||
if ((totlines != cm.totlines) ||
|
||||
(progressive != cm.progressive) ||
|
||||
(pcnt_frame < (cm.pcnt_frame - PCNT_TOLERANCE)) ||
|
||||
(pcnt_frame > (cm.pcnt_frame + PCNT_TOLERANCE))) {
|
||||
printf("totlines: %lu (cur) / %lu (prev), pcnt_frame: %lu (cur) / %lu (prev). VSM: %u\n", totlines, cm.totlines, pcnt_frame, cm.pcnt_frame, vsyncmode);
|
||||
/*if (!cm.sync_active)
|
||||
act_ctr = 0;*/
|
||||
stable_frames = 0;
|
||||
} else if (stable_frames != STABLE_THOLD) {
|
||||
stable_frames++;
|
||||
if (stable_frames == STABLE_THOLD)
|
||||
status = (status < MODE_CHANGE) ? MODE_CHANGE : status;
|
||||
printf("totlines: %lu (cur) / %lu (prev), pcnt_frame: %lu (cur) / %lu (prev)\n", totlines, cm.totlines, pcnt_frame, cm.pcnt_frame);
|
||||
|
||||
status = (status < MODE_CHANGE) ? MODE_CHANGE : status;
|
||||
}
|
||||
|
||||
if ((tc.pm_240p != cm.cc.pm_240p) ||
|
||||
@ -391,28 +359,23 @@ status_t get_status(tvp_sync_input_t syncinput)
|
||||
(tc.l4_mode != cm.cc.l4_mode) ||
|
||||
(tc.l5_mode != cm.cc.l5_mode) ||
|
||||
(tc.l5_fmt != cm.cc.l5_fmt) ||
|
||||
(tc.tvp_hpll2x != cm.cc.tvp_hpll2x) ||
|
||||
(tc.upsample2x != cm.cc.upsample2x) ||
|
||||
(tc.vga_ilace_fix != cm.cc.vga_ilace_fix) ||
|
||||
(tc.ar_256col != cm.cc.ar_256col) ||
|
||||
(tc.default_vic != cm.cc.default_vic) ||
|
||||
(tc.clamp_offset != cm.cc.clamp_offset))
|
||||
status = (status < MODE_CHANGE) ? MODE_CHANGE : status;
|
||||
|
||||
if ((tc.s480p_mode != cm.cc.s480p_mode) && (video_modes[cm.id].v_total == 525))
|
||||
if ((tc.s480p_mode != cm.cc.s480p_mode) && (vmode_in.timings.v_total == 525))
|
||||
status = (status < MODE_CHANGE) ? MODE_CHANGE : status;
|
||||
|
||||
if ((tc.s400p_mode != cm.cc.s400p_mode) && (video_modes[cm.id].v_total == 449))
|
||||
if ((tc.s400p_mode != cm.cc.s400p_mode) && (vmode_in.timings.v_total == 449))
|
||||
status = (status < MODE_CHANGE) ? MODE_CHANGE : status;
|
||||
|
||||
if (cm.pll_config != pll_reconfig->pll_config_status.c_config_id)
|
||||
if ((vm_conf.si_pclk_mult > 1) && (pll_reconfig->pll_config_status.c_config_id != 5) && (vm_conf.si_pclk_mult-1 != pll_reconfig->pll_config_status.c_config_id))
|
||||
status = (status < MODE_CHANGE) ? MODE_CHANGE : status;
|
||||
|
||||
if (update_cur_vm) {
|
||||
cm.h_mult_total = (video_modes[cm.id].h_total*cm.sample_mult) + ((cm.sample_mult*video_modes[cm.id].h_total_adj*5 + 50) / 100);
|
||||
tvp_setup_hpll(cm.h_mult_total, totlines, cm.cc.tvp_hpll2x && (video_modes[cm.id].flags & MODE_PLLDIVBY2));
|
||||
cm.sample_sel = tvp_set_hpll_phase(video_modes[cm.id].sampler_phase, cm.sample_mult);
|
||||
status = (status < SC_CONFIG_CHANGE) ? SC_CONFIG_CHANGE : status;
|
||||
}
|
||||
if (update_cur_vm)
|
||||
status = (status < MODE_CHANGE) ? MODE_CHANGE : status;
|
||||
|
||||
cm.totlines = totlines;
|
||||
cm.clkcnt = clkcnt;
|
||||
@ -425,18 +388,17 @@ status_t get_status(tvp_sync_input_t syncinput)
|
||||
(tc.sl_hybr_str != cm.cc.sl_hybr_str) ||
|
||||
(tc.sl_method != cm.cc.sl_method) ||
|
||||
(tc.sl_str != cm.cc.sl_str) ||
|
||||
(tc.sl_cust_iv_x != cm.cc.sl_cust_iv_x) ||
|
||||
(tc.sl_cust_iv_y != cm.cc.sl_cust_iv_y) ||
|
||||
memcmp(tc.sl_cust_l_str, cm.cc.sl_cust_l_str, 5) ||
|
||||
memcmp(tc.sl_cust_c_str, cm.cc.sl_cust_c_str, 6) ||
|
||||
(tc.sl_altern != cm.cc.sl_altern) ||
|
||||
(tc.sl_altiv != cm.cc.sl_altiv) ||
|
||||
(tc.sl_id != cm.cc.sl_id) ||
|
||||
(tc.h_mask != cm.cc.h_mask) ||
|
||||
(tc.v_mask != cm.cc.v_mask) ||
|
||||
(tc.mask_br != cm.cc.mask_br) ||
|
||||
(tc.mask_color != cm.cc.mask_color) ||
|
||||
(tc.ar_256col != cm.cc.ar_256col) ||
|
||||
(tc.reverse_lpf != cm.cc.reverse_lpf) ||
|
||||
(tc.panasonic_hack != cm.cc.panasonic_hack))
|
||||
(tc.reverse_lpf != cm.cc.reverse_lpf))
|
||||
status = (status < SC_CONFIG_CHANGE) ? SC_CONFIG_CHANGE : status;
|
||||
|
||||
if (tc.sync_vth != cm.cc.sync_vth)
|
||||
@ -479,6 +441,12 @@ status_t get_status(tvp_sync_input_t syncinput)
|
||||
|
||||
if (pcm1862_active && (tc.audio_gain != cm.cc.audio_gain))
|
||||
pcm_set_gain(tc.audio_gain-AUDIO_GAIN_0DB);
|
||||
|
||||
if (pcm1862_active && (tc.audio_mono != cm.cc.audio_mono)) {
|
||||
DisableAudioOutput();
|
||||
pcm_set_stereo_mode(tc.audio_mono);
|
||||
SetupAudio(cm.cc.tx_mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
cm.cc = tc;
|
||||
@ -487,289 +455,244 @@ status_t get_status(tvp_sync_input_t syncinput)
|
||||
return status;
|
||||
}
|
||||
|
||||
void update_sc_config()
|
||||
void update_sc_config(mode_data_t *vm_in, mode_data_t *vm_out, vm_proc_config_t *vm_conf, avconfig_t *avconfig)
|
||||
{
|
||||
int i;
|
||||
|
||||
hv_config_reg hv_in_config = {.data=0x00000000};
|
||||
hv_config2_reg hv_in_config2 = {.data=0x00000000};
|
||||
hv_config3_reg hv_in_config3 = {.data=0x00000000};
|
||||
hv_config_reg hv_out_config = {.data=0x00000000};
|
||||
hv_config2_reg hv_out_config2 = {.data=0x00000000};
|
||||
hv_config3_reg hv_out_config3 = {.data=0x00000000};
|
||||
xy_config_reg xy_out_config = {.data=0x00000000};
|
||||
xy_config2_reg xy_out_config2 = {.data=0x00000000};
|
||||
misc_config_reg misc_config = {.data=0x00000000};
|
||||
sl_config_reg sl_config = {.data=0x00000000};
|
||||
sl_config2_reg sl_config2 = {.data=0x00000000};
|
||||
sl_config3_reg sl_config3 = {.data=0x00000000};
|
||||
|
||||
alt_u8 sl_no_altern = 0;
|
||||
alt_u8 sl_l_overlay = 0, sl_c_overlay = 0;
|
||||
alt_u32 sl_l_str_arr = 0, sl_c_str_arr = 0;
|
||||
// Set input params
|
||||
hv_in_config.h_total = vm_in->timings.h_total;
|
||||
hv_in_config.h_active = vm_in->timings.h_active;
|
||||
hv_in_config.h_synclen = vm_in->timings.h_synclen;
|
||||
hv_in_config2.h_backporch = vm_in->timings.h_backporch;
|
||||
hv_in_config2.v_active = vm_in->timings.v_active;
|
||||
hv_in_config3.v_synclen = vm_in->timings.v_synclen;
|
||||
hv_in_config3.v_backporch = vm_in->timings.v_backporch;
|
||||
hv_in_config2.interlaced = vm_in->timings.interlaced;
|
||||
hv_in_config3.v_startline = vm_in->timings.v_synclen+vm_in->timings.v_backporch+12;
|
||||
hv_in_config3.h_skip = vm_conf->h_skip;
|
||||
hv_in_config3.h_sample_sel = vm_conf->h_sample_sel;
|
||||
|
||||
alt_u8 h_opt_scale = cm.sample_mult;
|
||||
alt_u16 h_opt_startoffs = 0;
|
||||
alt_u16 h_synclen = video_modes[cm.id].h_synclen;
|
||||
alt_u16 h_border, h_mask;
|
||||
alt_u16 v_active = video_modes[cm.id].v_active;
|
||||
alt_u16 v_backporch = video_modes[cm.id].v_backporch;
|
||||
// Set output params
|
||||
hv_out_config.h_total = vm_out->timings.h_total;
|
||||
hv_out_config.h_active = vm_out->timings.h_active;
|
||||
hv_out_config.h_synclen = vm_out->timings.h_synclen;
|
||||
hv_out_config2.h_backporch = vm_out->timings.h_backporch;
|
||||
hv_out_config2.v_total = vm_out->timings.v_total;
|
||||
hv_out_config2.v_active = vm_out->timings.v_active;
|
||||
hv_out_config3.v_synclen = vm_out->timings.v_synclen;
|
||||
hv_out_config3.v_backporch = vm_out->timings.v_backporch;
|
||||
hv_out_config2.interlaced = vm_out->timings.interlaced;
|
||||
hv_out_config3.v_startline = vm_conf->framesync_line;
|
||||
|
||||
int i;
|
||||
xy_out_config.x_size = vm_conf->x_size;
|
||||
xy_out_config.y_size = vm_conf->y_size;
|
||||
xy_out_config.y_offset = vm_conf->y_offset;
|
||||
xy_out_config2.x_offset = vm_conf->x_offset;
|
||||
xy_out_config2.x_start_lb = vm_conf->x_start_lb;
|
||||
xy_out_config2.y_start_lb = vm_conf->y_start_lb;
|
||||
xy_out_config2.x_rpt = vm_conf->x_rpt;
|
||||
xy_out_config2.y_rpt = vm_conf->y_rpt;
|
||||
|
||||
// construct default scanline overlay
|
||||
if ((cm.cc.sl_type == 0) || (cm.cc.sl_type == 2)) {
|
||||
if (cm.cc.sl_altiv) {
|
||||
sl_l_overlay = 1<<(cm.cc.sl_id);
|
||||
misc_config.mask_br = avconfig->mask_br;
|
||||
misc_config.mask_color = avconfig->mask_color;
|
||||
misc_config.reverse_lpf = avconfig->reverse_lpf;
|
||||
misc_config.lm_deint_mode = 0;
|
||||
misc_config.nir_even_offset = 0;
|
||||
misc_config.ypbpr_cs = (avconfig->ypbpr_cs == 0) ? ((vm_in->type & VIDEO_HDTV) ? 1 : 0) : avconfig->ypbpr_cs-1;
|
||||
misc_config.vip_enable = 0;
|
||||
misc_config.bfi_enable = 0;
|
||||
misc_config.bfi_str = 0;
|
||||
|
||||
// set default/custom scanline interval
|
||||
sl_def_iv_y = (vm_conf->y_rpt > 0) ? vm_conf->y_rpt : 1;
|
||||
sl_def_iv_x = (vm_conf->x_rpt > 0) ? vm_conf->x_rpt : sl_def_iv_y;
|
||||
sl_config3.sl_iv_x = ((avconfig->sl_type == 3) && (avconfig->sl_cust_iv_x)) ? avconfig->sl_cust_iv_x : sl_def_iv_x;
|
||||
sl_config3.sl_iv_y = ((avconfig->sl_type == 3) && (avconfig->sl_cust_iv_y)) ? avconfig->sl_cust_iv_y : sl_def_iv_y;
|
||||
|
||||
// construct custom/default scanline overlay
|
||||
for (i=0; i<6; i++) {
|
||||
if (avconfig->sl_type == 3) {
|
||||
sl_config.sl_l_str_arr |= ((avconfig->sl_cust_l_str[i]-1)&0xf)<<(4*i);
|
||||
sl_config.sl_l_overlay |= (avconfig->sl_cust_l_str[i]!=0)<<i;
|
||||
} else {
|
||||
switch (cm.fpga_vmultmode) {
|
||||
case FPGA_V_MULTMODE_3X:
|
||||
sl_l_overlay = 1<<(2*(cm.cc.sl_id));
|
||||
break;
|
||||
case FPGA_V_MULTMODE_4X:
|
||||
sl_l_overlay = 3<<(2*(cm.cc.sl_id));
|
||||
break;
|
||||
case FPGA_V_MULTMODE_5X:
|
||||
sl_l_overlay = 3<<(3*(cm.cc.sl_id));
|
||||
break;
|
||||
default: //1x, 2x
|
||||
sl_l_overlay = 1<<(cm.cc.sl_id);
|
||||
break;
|
||||
sl_config.sl_l_str_arr |= avconfig->sl_str<<(4*i);
|
||||
|
||||
if ((i==5) && ((avconfig->sl_type == 0) || (avconfig->sl_type == 2))) {
|
||||
sl_config.sl_l_overlay = (1<<((sl_config3.sl_iv_y+1)/2))-1;
|
||||
if (avconfig->sl_id)
|
||||
sl_config.sl_l_overlay <<= (sl_config3.sl_iv_y+2)/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((cm.cc.sl_type == 1) || (cm.cc.sl_type == 2)) {
|
||||
if (cm.sample_mult <= 4)
|
||||
sl_c_overlay = (1<<((cm.sample_mult-1)*(cm.cc.sl_id)));
|
||||
else
|
||||
sl_c_overlay = (3<<((cm.sample_mult-2)*(cm.cc.sl_id)));
|
||||
}
|
||||
// construct custom scanline overlay and strength arrays
|
||||
for (i=0; i<5; i++) {
|
||||
if (cm.cc.sl_type == 3) {
|
||||
sl_l_str_arr |= ((cm.cc.sl_cust_l_str[i]-1)&0xf)<<(4*i);
|
||||
sl_l_overlay |= (cm.cc.sl_cust_l_str[i]!=0)<<i;
|
||||
for (i=0; i<10; i++) {
|
||||
if (avconfig->sl_type == 3) {
|
||||
if (i<8)
|
||||
sl_config2.sl_c_str_arr_l |= ((avconfig->sl_cust_c_str[i]-1)&0xf)<<(4*i);
|
||||
else
|
||||
sl_config3.sl_c_str_arr_h |= ((avconfig->sl_cust_c_str[i]-1)&0xf)<<(4*(i-8));
|
||||
sl_config3.sl_c_overlay |= (avconfig->sl_cust_c_str[i]!=0)<<i;
|
||||
} else {
|
||||
sl_l_str_arr |= cm.cc.sl_str<<(4*i);
|
||||
if (i<8)
|
||||
sl_config2.sl_c_str_arr_l |= avconfig->sl_str<<(4*i);
|
||||
else
|
||||
sl_config3.sl_c_str_arr_h |= avconfig->sl_str<<(4*(i-8));
|
||||
|
||||
if ((i==9) && ((avconfig->sl_type == 1) || (avconfig->sl_type == 2)))
|
||||
sl_config3.sl_c_overlay = (1<<((sl_config3.sl_iv_x+1)/2))-1;
|
||||
}
|
||||
}
|
||||
for (i=0; i<6; i++) {
|
||||
if (cm.cc.sl_type == 3) {
|
||||
sl_c_str_arr |= ((cm.cc.sl_cust_c_str[i]-1)&0xf)<<(4*i);
|
||||
sl_c_overlay |= (cm.cc.sl_cust_c_str[i]!=0)<<i;
|
||||
} else {
|
||||
sl_c_str_arr |= cm.cc.sl_str<<(4*i);
|
||||
}
|
||||
sl_config.sl_method = avconfig->sl_method;
|
||||
sl_config.sl_altern = avconfig->sl_altern;
|
||||
|
||||
// disable scanlines if configured so
|
||||
if (((avconfig->sl_mode == 1) && (!vm_conf->y_rpt)) || (avconfig->sl_mode == 0)) {
|
||||
sl_config.sl_l_overlay = 0;
|
||||
sl_config3.sl_c_overlay = 0;
|
||||
}
|
||||
// enable/disable alternating scanlines
|
||||
if ((video_modes[cm.id].flags & MODE_INTERLACED) && (cm.fpga_vmultmode))
|
||||
sl_no_altern = !cm.cc.sl_altern;
|
||||
// oevrride scanline mode
|
||||
if (cm.cc.sl_mode == 1) { //auto
|
||||
//disable scanlines
|
||||
if ((cm.fpga_vmultmode==0) || (video_modes[cm.id].group == GROUP_480P)) {
|
||||
sl_l_overlay = 0;
|
||||
sl_c_overlay = 0;
|
||||
}
|
||||
} else if (cm.cc.sl_mode == 0) { //off
|
||||
//disable scanlines
|
||||
sl_l_overlay = 0;
|
||||
sl_c_overlay = 0;
|
||||
}
|
||||
|
||||
switch (cm.target_lm) {
|
||||
case MODE_L2_240x360:
|
||||
h_opt_scale = 4;
|
||||
break;
|
||||
case MODE_L2_256_COL:
|
||||
h_opt_scale = 6-2*cm.cc.ar_256col;
|
||||
break;
|
||||
case MODE_L3_320_COL:
|
||||
h_opt_scale = 3;
|
||||
break;
|
||||
case MODE_L3_256_COL:
|
||||
h_opt_scale = 4-cm.cc.ar_256col;
|
||||
break;
|
||||
case MODE_L3_240x360:
|
||||
h_opt_scale = 6;
|
||||
break;
|
||||
case MODE_L4_256_COL:
|
||||
h_opt_scale = 5-cm.cc.ar_256col;
|
||||
break;
|
||||
case MODE_L5_256_COL:
|
||||
h_opt_scale = 6-cm.cc.ar_256col;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cm.target_lm >= MODE_L5_GEN_4_3 && cm.cc.l5_fmt == L5FMT_1920x1080) {
|
||||
v_active -= 24;
|
||||
v_backporch += 12;
|
||||
}
|
||||
|
||||
// CEA-770.3 HDTV modes use tri-level syncs which have twice the width of bi-level syncs of corresponding CEA-861 modes
|
||||
if (target_type == VIDEO_HDTV)
|
||||
h_synclen *= 2;
|
||||
|
||||
// 1920x* modes need short hsync
|
||||
if (h_synclen > cm.hsync_cut)
|
||||
h_synclen -= cm.hsync_cut;
|
||||
else
|
||||
h_synclen = 1;
|
||||
|
||||
h_border = (((cm.sample_mult-h_opt_scale)*video_modes[cm.id].h_active)/2);
|
||||
h_mask = h_border + h_opt_scale*cm.cc.h_mask;
|
||||
h_opt_startoffs = h_border + (cm.sample_mult-h_opt_scale)*(h_synclen+(alt_u16)video_modes[cm.id].h_backporch);
|
||||
printf("h_border: %u, h_opt_startoffs: %u\n", h_border, h_opt_startoffs);
|
||||
|
||||
misc_config.h_multmode = cm.fpga_hmultmode;
|
||||
//misc_config.h_l5fmt = (cm.cc.l5_fmt!=L5FMT_1600x1200);
|
||||
misc_config.h_l3_240x360 = (cm.target_lm==MODE_L3_240x360);
|
||||
|
||||
hv_in_config.h_total = video_modes[cm.id].h_total;
|
||||
hv_in_config.h_synclen = (cm.sample_mult*h_synclen);
|
||||
hv_in_config2.h_backporch = (cm.sample_mult*(alt_u16)video_modes[cm.id].h_backporch);
|
||||
hv_in_config.h_active = (cm.sample_mult*video_modes[cm.id].h_active);
|
||||
|
||||
//h_config2.h_mask = h_mask;
|
||||
misc_config.h_opt_scale = h_opt_scale;
|
||||
hv_in_config3.h_sample_sel = cm.sample_sel;
|
||||
hv_in_config3.h_skip = cm.sample_mult;
|
||||
misc_config.h_opt_startoff = h_opt_startoffs;
|
||||
|
||||
misc_config.v_multmode = cm.fpga_vmultmode;
|
||||
//v_config.v_mask = cm.cc.v_mask;
|
||||
hv_in_config3.v_synclen = video_modes[cm.id].v_synclen;
|
||||
hv_in_config3.v_backporch = v_backporch;
|
||||
hv_in_config2.v_active = v_active;
|
||||
//hv_in_config2.v_total = v_total;
|
||||
|
||||
misc_config.rev_lpf_str = cm.cc.reverse_lpf;
|
||||
misc_config.mask_br = cm.cc.mask_br;
|
||||
misc_config.mask_color = cm.cc.mask_color;
|
||||
misc_config.panasonic_hack = cm.cc.panasonic_hack;
|
||||
|
||||
sl_config.sl_l_str_arr = sl_l_str_arr;
|
||||
sl_config.sl_l_overlay = sl_l_overlay;
|
||||
sl_config.sl_hybr_str = cm.cc.sl_hybr_str;
|
||||
sl_config.sl_method = cm.cc.sl_method;
|
||||
sl_config.sl_no_altern = sl_no_altern;
|
||||
|
||||
sl_config2.sl_c_str_arr = sl_c_str_arr;
|
||||
sl_config2.sl_c_overlay = sl_c_overlay;
|
||||
sl_config2.sl_altiv = cm.cc.sl_altiv;
|
||||
|
||||
sc->hv_in_config = hv_in_config;
|
||||
sc->hv_in_config2 = hv_in_config2;
|
||||
sc->hv_in_config3 = hv_in_config3;
|
||||
sc->hv_out_config = hv_out_config;
|
||||
sc->hv_out_config2 = hv_out_config2;
|
||||
sc->hv_out_config3 = hv_out_config3;
|
||||
sc->xy_out_config = xy_out_config;
|
||||
sc->xy_out_config2 = xy_out_config2;
|
||||
sc->misc_config = misc_config;
|
||||
sc->sl_config = sl_config;
|
||||
sc->sl_config2 = sl_config2;
|
||||
sc->sl_config3 = sl_config3;
|
||||
}
|
||||
|
||||
// Configure TVP7002 and scan converter logic based on the video mode
|
||||
void program_mode()
|
||||
{
|
||||
alt_u8 h_syncinlen, v_syncinlen, hdmitx_pclk_level, osd_x_size, osd_y_size;
|
||||
alt_u32 h_hz, v_hz_x100, h_synclen_px;
|
||||
alt_u8 h_syncinlen, v_syncinlen, macrovis, hdmitx_pclk_level, osd_x_size, osd_y_size;
|
||||
alt_u32 h_hz, h_synclen_px, pclk_i_hz, dotclk_hz, pll_h_total;
|
||||
|
||||
// Mark as stable (needed after sync up to avoid unnecessary mode switch)
|
||||
stable_frames = STABLE_THOLD;
|
||||
memset(&vmode_in, 0, sizeof(mode_data_t));
|
||||
cm.tx_pixelrep = cm.hdmitx_pixr_ifr = 0;
|
||||
|
||||
if ((cm.clkcnt != 0) && (cm.totlines != 0)) { //prevent div by 0
|
||||
h_hz = TVP_EXTCLK_HZ/cm.clkcnt;
|
||||
v_hz_x100 = (100*TVP_EXTCLK_HZ)/cm.pcnt_frame;
|
||||
} else {
|
||||
h_hz = 15700;
|
||||
v_hz_x100 = 6000;
|
||||
}
|
||||
vmode_in.timings.v_hz_x100 = (100*27000000UL)/cm.pcnt_frame;
|
||||
h_hz = (100*27000000UL)/((100*cm.pcnt_frame*(1+!cm.progressive))/cm.totlines);
|
||||
|
||||
printf("\nLines: %u %c\n", (unsigned)cm.totlines, cm.progressive ? 'p' : 'i');
|
||||
printf("Clocks per line: %u : HS %u.%.3u kHz VS %u.%.2u Hz\n", (unsigned)cm.clkcnt, (unsigned)(h_hz/1000), (unsigned)(h_hz%1000), (unsigned)(v_hz_x100/100), (unsigned)(v_hz_x100%100));
|
||||
printf("Clocks per line: %u\n", (unsigned)cm.clkcnt);
|
||||
|
||||
h_syncinlen = tvp_readreg(TVP_HSINWIDTH);
|
||||
v_syncinlen = tvp_readreg(TVP_VSINWIDTH);
|
||||
printf("Hswidth: %u Vswidth: %u Macrovision: %u\n", (unsigned)h_syncinlen, (unsigned)(v_syncinlen & 0x1F), (unsigned)cm.macrovis);
|
||||
macrovis = !!(tvp_readreg(TVP_LINECNT2) & (1<<6));
|
||||
printf("Hswidth: %u Vswidth: %u Macrovision: %u\n", (unsigned)h_syncinlen, (unsigned)(v_syncinlen & 0x1F), (unsigned)macrovis);
|
||||
|
||||
vmode_in.timings.h_synclen = h_syncinlen;
|
||||
vmode_in.timings.v_total = cm.totlines;
|
||||
vmode_in.timings.interlaced = !cm.progressive;
|
||||
|
||||
sniprintf(row1, LCD_ROW_LEN+1, "%s %u-%c", avinput_str[cm.avinput], (unsigned)cm.totlines, cm.progressive ? 'p' : 'i');
|
||||
sniprintf(row2, LCD_ROW_LEN+1, "%u.%.2ukHz %u.%.2uHz", (unsigned)(h_hz/1000), (unsigned)((h_hz%1000)/10), (unsigned)(v_hz_x100/100), (unsigned)(v_hz_x100%100));
|
||||
sniprintf(row2, LCD_ROW_LEN+1, "%u.%.2ukHz %u.%.2uHz", (unsigned)(h_hz/1000), (unsigned)((h_hz%1000)/10), (unsigned)(vmode_in.timings.v_hz_x100/100), (unsigned)(vmode_in.timings.v_hz_x100%100));
|
||||
ui_disp_status(1);
|
||||
|
||||
//printf ("Get mode id with %u %u %f\n", totlines, progressive, hz);
|
||||
cm.id = get_mode_id(cm.totlines, cm.progressive, v_hz_x100/100, h_syncinlen);
|
||||
cm.id = get_pure_lm_mode(&cm.cc, &vmode_in, &vmode_out, &vm_conf);
|
||||
|
||||
if (cm.id == -1) {
|
||||
printf ("Error: no suitable mode found, defaulting to 240p\n");
|
||||
cm.id = 4;
|
||||
printf ("ERROR: no suitable mode preset found\n");
|
||||
vm_conf.si_pclk_mult = 0;
|
||||
return;
|
||||
}
|
||||
vm_sel = cm.id;
|
||||
|
||||
cm.h_mult_total = (video_modes[cm.id].h_total*cm.sample_mult) + ((cm.sample_mult*video_modes[cm.id].h_total_adj*5 + 50) / 100);
|
||||
// Double TVP7002 PLL sampling rate when possible to minimize jitter
|
||||
while (1) {
|
||||
pll_h_total = (vm_conf.h_skip+1) * vmode_in.timings.h_total + (((vm_conf.h_skip+1) * vmode_in.timings.h_total_adj * 5 + 50) / 100);
|
||||
pclk_i_hz = h_hz * pll_h_total;
|
||||
|
||||
if ((pclk_i_hz < 25000000UL) && ((vm_conf.si_pclk_mult % 2) == 0)) {
|
||||
vm_conf.h_skip = 2*(vm_conf.h_skip+1)-1;
|
||||
vm_conf.si_pclk_mult /= 2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Tweak infoframe pixel repetition indicator if passing thru horizontally multiplied mode
|
||||
if ((vm_conf.y_rpt == 0) && (vm_conf.h_skip > 0))
|
||||
cm.hdmitx_pixr_ifr = vm_conf.h_skip;
|
||||
|
||||
dotclk_hz = estimate_dotclk(&vmode_in, h_hz);
|
||||
cm.pclk_o_hz = calculate_pclk(pclk_i_hz, &vmode_out, &vm_conf);
|
||||
|
||||
printf("H: %lu.%.2lukHz V: %u.%.2uHz\n", (h_hz+5)/1000, ((h_hz+5)%1000)/10, (vmode_in.timings.v_hz_x100/100), (vmode_in.timings.v_hz_x100%100));
|
||||
printf("Estimated source dot clock: %lu.%.2luMHz\n", (dotclk_hz+5000)/1000000, ((dotclk_hz+5000)%1000000)/10000);
|
||||
printf("PCLK_IN: %luHz PCLK_OUT: %luHz\n", pclk_i_hz, cm.pclk_o_hz);
|
||||
|
||||
// Trilevel sync is used with HDTV modes using composite sync
|
||||
if (video_modes[cm.id].type & VIDEO_HDTV)
|
||||
if (video_modes_plm[cm.id].type & VIDEO_HDTV)
|
||||
target_type = (target_tvp_sync <= TVP_SOG3) ? VIDEO_HDTV : VIDEO_PC;
|
||||
else
|
||||
target_type = video_modes[cm.id].type;
|
||||
target_type = video_modes_plm[cm.id].type;
|
||||
|
||||
h_synclen_px = ((alt_u32)h_syncinlen * (alt_u32)cm.h_mult_total) / cm.clkcnt;
|
||||
h_synclen_px = ((alt_u32)h_syncinlen * pll_h_total) / cm.clkcnt;
|
||||
|
||||
printf("Mode %s selected - hsync width: %upx\n", video_modes[cm.id].name, (unsigned)h_synclen_px);
|
||||
printf("Mode %s selected - hsync width: %upx\n", video_modes_plm[cm.id].name, (unsigned)h_synclen_px);
|
||||
|
||||
tvp_source_setup(target_type,
|
||||
cm.h_mult_total,
|
||||
pll_h_total,
|
||||
cm.clkcnt,
|
||||
cm.cc.tvp_hpll2x && (video_modes[cm.id].flags & MODE_PLLDIVBY2),
|
||||
0,
|
||||
(alt_u8)h_synclen_px,
|
||||
(alt_8)(cm.cc.clamp_offset-SIGNED_NUMVAL_ZERO));
|
||||
set_lpf(cm.cc.video_lpf);
|
||||
set_csc(cm.cc.ypbpr_cs);
|
||||
cm.sample_sel = tvp_set_hpll_phase(video_modes[cm.id].sampler_phase, cm.sample_mult);
|
||||
|
||||
pll_reconfig->pll_config_status.reset = (cm.fpga_vmultmode == FPGA_V_MULTMODE_1X);
|
||||
set_sampler_phase(video_modes_plm[cm.id].sampler_phase);
|
||||
|
||||
switch (cm.fpga_vmultmode) {
|
||||
case FPGA_V_MULTMODE_2X:
|
||||
case FPGA_V_MULTMODE_5X:
|
||||
cm.pll_config = PLL_CONFIG_2X_5X;
|
||||
break;
|
||||
case FPGA_V_MULTMODE_3X:
|
||||
case FPGA_V_MULTMODE_4X:
|
||||
cm.pll_config = PLL_CONFIG_3X_4X;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pll_reconfigure(cm.pll_config);
|
||||
pll_reconfig->pll_config_status.reset = (vm_conf.si_pclk_mult <= 1);
|
||||
|
||||
if (cm.fpga_vmultmode == FPGA_V_MULTMODE_1X) {
|
||||
osd_y_size = (video_modes[cm.id].v_active > 700) ? 1 : 0;
|
||||
osd_x_size = osd_y_size + !!(video_modes[cm.id].flags & MODE_INTERLACED);
|
||||
if (vm_conf.si_pclk_mult > 1) {
|
||||
if ((vm_conf.si_pclk_mult == 2) && (pclk_i_hz > 50000000UL))
|
||||
pll_reconfigure(5);
|
||||
else
|
||||
pll_reconfigure(vm_conf.si_pclk_mult-1);
|
||||
sys_ctrl &= ~PLL_BYPASS;
|
||||
} else {
|
||||
osd_x_size = 1 - cm.tx_pixelrep + (cm.fpga_hmultmode == FPGA_H_MULTMODE_OPTIMIZED_1X) + (cm.fpga_vmultmode > FPGA_V_MULTMODE_3X);
|
||||
osd_y_size = 0;
|
||||
sys_ctrl |= PLL_BYPASS;
|
||||
}
|
||||
osd->osd_config.x_size = osd_x_size;
|
||||
osd->osd_config.y_size = osd_y_size;
|
||||
IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, sys_ctrl);
|
||||
|
||||
update_sc_config();
|
||||
update_osd_size(&vmode_out);
|
||||
|
||||
update_sc_config(&vmode_in, &vmode_out, &vm_conf, &cm.cc);
|
||||
|
||||
TX_SetPixelRepetition(cm.tx_pixelrep, ((cm.cc.tx_mode!=TX_DVI) && (cm.tx_pixelrep == cm.hdmitx_pixr_ifr)) ? 1 : 0);
|
||||
|
||||
pclk_out = (TVP_EXTCLK_HZ/cm.clkcnt)*cm.h_mult_total*(cm.fpga_vmultmode+1);
|
||||
pclk_out *= 1+cm.tx_pixelrep;
|
||||
if (cm.fpga_hmultmode == FPGA_H_MULTMODE_OPTIMIZED_1X)
|
||||
pclk_out /= 2;
|
||||
else if (cm.fpga_hmultmode == FPGA_H_MULTMODE_ASPECTFIX)
|
||||
pclk_out = (pclk_out*4)/3;
|
||||
printf("PCLK_out: %luHz\n", pclk_out);
|
||||
|
||||
if (pclk_out > 85000000)
|
||||
if (cm.pclk_o_hz > 85000000)
|
||||
hdmitx_pclk_level = 1;
|
||||
else if (pclk_out < 75000000)
|
||||
else if (cm.pclk_o_hz < 75000000)
|
||||
hdmitx_pclk_level = 0;
|
||||
else
|
||||
hdmitx_pclk_level = cm.hdmitx_pclk_level;
|
||||
|
||||
printf("PCLK level: %u, PR: %u, IPR: %u, ITC: %u\n", hdmitx_pclk_level, cm.tx_pixelrep, cm.hdmitx_pixr_ifr, cm.cc.hdmi_itc);
|
||||
|
||||
// Full TX initialization increases mode switch delay, use only when necessary
|
||||
if (cm.cc.full_tx_setup || (cm.hdmitx_pclk_level != hdmitx_pclk_level)) {
|
||||
cm.hdmitx_pclk_level = hdmitx_pclk_level;
|
||||
TX_enable(cm.cc.tx_mode);
|
||||
} else if (cm.cc.tx_mode!=TX_DVI) {
|
||||
HDMITX_SetAVIInfoFrame(cm.hdmitx_vic, (cm.cc.tx_mode == TX_HDMI_RGB) ? F_MODE_RGB444 : F_MODE_YUV444, 0, 0, cm.cc.hdmi_itc, cm.hdmitx_pixr_ifr);
|
||||
HDMITX_SetAVIInfoFrame(vmode_out.vic, (cm.cc.tx_mode == TX_HDMI_RGB) ? F_MODE_RGB444 : F_MODE_YUV444, 0, 0, cm.cc.hdmi_itc, cm.hdmitx_pixr_ifr);
|
||||
#ifdef ENABLE_AUDIO
|
||||
#ifdef MANUAL_CTS
|
||||
SetupAudio(cm.cc.tx_mode);
|
||||
@ -885,21 +808,18 @@ int init_hw()
|
||||
memcpy(&cm.cc, &tc_default, sizeof(avconfig_t));
|
||||
memcpy(rc_keymap, rc_keymap_default, sizeof(rc_keymap));
|
||||
|
||||
// Init menu
|
||||
init_menu();
|
||||
|
||||
// Load initconfig and profile
|
||||
read_userdata(INIT_CONFIG_SLOT, 0);
|
||||
read_userdata(profile_sel, 0);
|
||||
|
||||
// Setup OSD
|
||||
osd->osd_config.x_size = 0;
|
||||
osd->osd_config.y_size = 0;
|
||||
osd->osd_config.x_offset = 3;
|
||||
osd->osd_config.y_offset = 3;
|
||||
osd->osd_config.enable = !!osd_enable;
|
||||
osd->osd_config.status_timeout = osd_status_timeout;
|
||||
osd->osd_config.border_color = 1;
|
||||
// Setup test pattern
|
||||
get_vmode(VMODE_480p, &vmode_in, &vmode_out, &vm_conf);
|
||||
update_sc_config(&vmode_in, &vmode_out, &vm_conf, &cm.cc);
|
||||
|
||||
// init always in HDMI mode (fixes yellow screen bug)
|
||||
cm.hdmitx_vic = HDMI_480p60;
|
||||
TX_enable(TX_HDMI_RGB);
|
||||
|
||||
// Setup remote keymap
|
||||
@ -909,6 +829,39 @@ int init_hw()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_vm_stats() {
|
||||
int row = 0;
|
||||
|
||||
if (!menu_active) {
|
||||
memset((void*)osd->osd_array.data, 0, sizeof(osd_char_array));
|
||||
read_userdata(profile_sel, 1);
|
||||
|
||||
sniprintf((char*)osd->osd_array.data[row][0], OSD_CHAR_COLS, "Mode preset:");
|
||||
sniprintf((char*)osd->osd_array.data[row][1], OSD_CHAR_COLS, "%s", vmode_out.name);
|
||||
sniprintf((char*)osd->osd_array.data[++row][0], OSD_CHAR_COLS, "Refresh rate:");
|
||||
sniprintf((char*)osd->osd_array.data[row][1], OSD_CHAR_COLS, "%u.%.2uHz", vmode_out.timings.v_hz_x100/100, vmode_out.timings.v_hz_x100%100);
|
||||
sniprintf((char*)osd->osd_array.data[++row][0], OSD_CHAR_COLS, "H/V synclen:");
|
||||
sniprintf((char*)osd->osd_array.data[row][1], OSD_CHAR_COLS, "%-5u %-5u", vmode_out.timings.h_synclen, vmode_out.timings.v_synclen);
|
||||
sniprintf((char*)osd->osd_array.data[++row][0], OSD_CHAR_COLS, "H/V backporch:");
|
||||
sniprintf((char*)osd->osd_array.data[row][1], OSD_CHAR_COLS, "%-5u %-5u", vmode_out.timings.h_backporch, vmode_out.timings.v_backporch);
|
||||
sniprintf((char*)osd->osd_array.data[++row][0], OSD_CHAR_COLS, "H/V active:");
|
||||
sniprintf((char*)osd->osd_array.data[row][1], OSD_CHAR_COLS, "%-5u %-5u", vmode_out.timings.h_active, vmode_out.timings.v_active);
|
||||
sniprintf((char*)osd->osd_array.data[++row][0], OSD_CHAR_COLS, "H/V total:");
|
||||
sniprintf((char*)osd->osd_array.data[row][1], OSD_CHAR_COLS, "%-5u %-5u", vmode_out.timings.h_total, vmode_out.timings.v_total);
|
||||
row++;
|
||||
|
||||
sniprintf((char*)osd->osd_array.data[++row][0], OSD_CHAR_COLS, "Profile:");
|
||||
sniprintf((char*)osd->osd_array.data[row][1], OSD_CHAR_COLS, "%u: %s", profile_sel, (target_profile_name[0] == 0) ? "<empty>" : target_profile_name);
|
||||
sniprintf((char*)osd->osd_array.data[++row][0], OSD_CHAR_COLS, "Firmware:");
|
||||
sniprintf((char*)osd->osd_array.data[row][1], OSD_CHAR_COLS, "%u.%.2u" FW_SUFFIX1 FW_SUFFIX2 " @ " __DATE__, FW_VER_MAJOR, FW_VER_MINOR);
|
||||
|
||||
osd->osd_config.status_refresh = 1;
|
||||
osd->osd_row_color.mask = 0;
|
||||
osd->osd_sec_enable[0].mask = (1<<(row+1))-1;
|
||||
osd->osd_sec_enable[1].mask = (1<<(row+1))-1;
|
||||
}
|
||||
}
|
||||
|
||||
int latency_test() {
|
||||
lt_status_reg lt_status;
|
||||
alt_u16 latency_ms_x100, stb_ms_x100;
|
||||
@ -970,18 +923,6 @@ int latency_test() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Enable chip outputs
|
||||
void enable_outputs()
|
||||
{
|
||||
// enable TVP output
|
||||
tvp_enable_output();
|
||||
// program video mode
|
||||
program_mode();
|
||||
|
||||
// enable and unmute TX
|
||||
TX_enable(tc.tx_mode);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
ths_input_t target_ths = 0;
|
||||
@ -1006,7 +947,7 @@ int main()
|
||||
printf("### DIY VIDEO DIGITIZER / SCANCONVERTER INIT OK ###\n\n");
|
||||
sniprintf(row1, LCD_ROW_LEN+1, "OSSC fw. %u.%.2u" FW_SUFFIX1 FW_SUFFIX2, FW_VER_MAJOR, FW_VER_MINOR);
|
||||
#ifndef DEBUG
|
||||
strncpy(row2, "2014-2022 marqs", LCD_ROW_LEN+1);
|
||||
strncpy(row2, "2014-2023 marqs", LCD_ROW_LEN+1);
|
||||
#else
|
||||
strncpy(row2, "** DEBUG BUILD *", LCD_ROW_LEN+1);
|
||||
#endif
|
||||
@ -1166,7 +1107,7 @@ int main()
|
||||
cm.avinput = target_input;
|
||||
cm.sync_active = 0;
|
||||
ths_source_sel(target_ths, (cm.cc.video_lpf > 1) ? (VIDEO_LPF_MAX-cm.cc.video_lpf) : THS_LPF_BYPASS);
|
||||
tvp_disable_output();
|
||||
tvp_powerdown();
|
||||
#ifdef ENABLE_AUDIO
|
||||
DisableAudioOutput();
|
||||
if (pcm1862_active)
|
||||
@ -1193,7 +1134,7 @@ int main()
|
||||
|
||||
// Check here to enable regardless of input
|
||||
if (tc.tx_mode != cm.cc.tx_mode) {
|
||||
HDMITX_SetAVIInfoFrame(cm.hdmitx_vic, F_MODE_RGB444, 0, 0, 0, 0);
|
||||
HDMITX_SetAVIInfoFrame(vmode_out.vic, F_MODE_RGB444, 0, 0, 0, 0);
|
||||
TX_enable(tc.tx_mode);
|
||||
cm.cc.tx_mode = tc.tx_mode;
|
||||
cm.clkcnt = 0; //TODO: proper invalidate
|
||||
@ -1201,7 +1142,7 @@ int main()
|
||||
if ((tc.tx_mode != TX_DVI) && (tc.hdmi_itc != cm.cc.hdmi_itc)) {
|
||||
//EnableAVIInfoFrame(FALSE, NULL);
|
||||
printf("setting ITC to %d\n", tc.hdmi_itc);
|
||||
HDMITX_SetAVIInfoFrame(cm.hdmitx_vic, (tc.tx_mode == TX_HDMI_RGB) ? F_MODE_RGB444 : F_MODE_YUV444, 0, 0, tc.hdmi_itc, cm.hdmitx_pixr_ifr);
|
||||
HDMITX_SetAVIInfoFrame(vmode_out.vic, (tc.tx_mode == TX_HDMI_RGB) ? F_MODE_RGB444 : F_MODE_YUV444, 0, 0, tc.hdmi_itc, cm.hdmitx_pixr_ifr);
|
||||
cm.cc.hdmi_itc = tc.hdmi_itc;
|
||||
}
|
||||
if (tc.av3_alt_rgb != cm.cc.av3_alt_rgb) {
|
||||
@ -1227,11 +1168,15 @@ int main()
|
||||
printf("Sync up\n");
|
||||
sys_ctrl |= VIDGEN_OFF;
|
||||
IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, sys_ctrl);
|
||||
enable_outputs();
|
||||
tvp_powerup();
|
||||
program_mode();
|
||||
#ifdef ENABLE_AUDIO
|
||||
SetupAudio(cm.cc.tx_mode);
|
||||
#endif
|
||||
} else {
|
||||
printf("Sync lost\n");
|
||||
cm.clkcnt = 0; //TODO: proper invalidate
|
||||
tvp_disable_output();
|
||||
tvp_powerdown();
|
||||
//ths_source_sel(THS_STANDBY, 0);
|
||||
strncpy(row1, avinput_str[cm.avinput], LCD_ROW_LEN+1);
|
||||
strncpy(row2, " NO SYNC", LCD_ROW_LEN+1);
|
||||
@ -1250,7 +1195,7 @@ int main()
|
||||
case SC_CONFIG_CHANGE:
|
||||
if (cm.sync_active) {
|
||||
printf("Scanconverter config change\n");
|
||||
update_sc_config();
|
||||
update_sc_config(&vmode_in, &vmode_out, &vm_conf, &cm.cc);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (C) 2015-2019 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
// Copyright (C) 2015-2023 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
//
|
||||
// This file is part of Open Source Scan Converter project.
|
||||
//
|
||||
@ -27,10 +27,11 @@
|
||||
#include "pll_reconfig_regs.h"
|
||||
|
||||
// sys_ctrl bits
|
||||
#define VSYNC_I_TYPE (1<<18)
|
||||
#define LT_ACTIVE (1<<15)
|
||||
#define LT_ARMED (1<<14)
|
||||
#define LT_MODE_OFFS 12
|
||||
#define VSYNC_I_TYPE (1<<10)
|
||||
#define PLL_BYPASS (1<<9)
|
||||
#define REMOTE_EVENT (1<<8)
|
||||
#define SD_SPI_SS_N (1<<7)
|
||||
#define LCD_CS_N (1<<6)
|
||||
@ -40,37 +41,18 @@
|
||||
#define VIDGEN_OFF (1<<1)
|
||||
#define AV_RESET_N (1<<0)
|
||||
|
||||
#define LT_CTRL_MASK 0xf000
|
||||
#define LT_CTRL_MASK 0xf000
|
||||
|
||||
// HDMI_TX definitions
|
||||
#define HDMITX_MODE_MASK 0x00040000
|
||||
|
||||
#define PLL_ACTIVECLK_MASK 0x00080000
|
||||
|
||||
#define TX_PIXELREP_DISABLE 0
|
||||
#define TX_PIXELREP_2X 1
|
||||
#define TX_PIXELREP_4X 3
|
||||
|
||||
// FPGA macros
|
||||
#define FPGA_V_MULTMODE_1X 0
|
||||
#define FPGA_V_MULTMODE_2X 1
|
||||
#define FPGA_V_MULTMODE_3X 2
|
||||
#define FPGA_V_MULTMODE_4X 3
|
||||
#define FPGA_V_MULTMODE_5X 4
|
||||
|
||||
#define FPGA_H_MULTMODE_FULLWIDTH 0
|
||||
#define FPGA_H_MULTMODE_ASPECTFIX 1
|
||||
#define FPGA_H_MULTMODE_OPTIMIZED 2
|
||||
#define FPGA_H_MULTMODE_OPTIMIZED_1X 3
|
||||
#define VSYNC_FLAG_MASK 0x00100000
|
||||
|
||||
#define AUTO_OFF 0
|
||||
#define AUTO_CURRENT_INPUT 1
|
||||
#define AUTO_MAX_COUNT 100
|
||||
#define AUTO_MAX_COUNT 100
|
||||
#define AUTO_CURRENT_MAX_COUNT 6
|
||||
|
||||
#define PLL_CONFIG_VG 0
|
||||
#define PLL_CONFIG_2X_5X 1
|
||||
#define PLL_CONFIG_3X_4X 2
|
||||
|
||||
// In reverse order of importance
|
||||
typedef enum {
|
||||
@ -97,22 +79,13 @@ typedef struct {
|
||||
alt_u32 pcnt_frame;
|
||||
alt_u32 clkcnt;
|
||||
alt_u8 progressive;
|
||||
alt_u8 macrovis;
|
||||
alt_8 id;
|
||||
alt_u8 sync_active;
|
||||
alt_u8 fpga_vmultmode;
|
||||
alt_u8 fpga_hmultmode;
|
||||
alt_u8 tx_pixelrep;
|
||||
alt_u8 hdmitx_pixr_ifr;
|
||||
alt_u8 hdmitx_pclk_level;
|
||||
HDMI_Video_Type hdmitx_vic;
|
||||
alt_u8 sample_mult;
|
||||
alt_u8 sample_sel;
|
||||
alt_u8 hsync_cut;
|
||||
alt_u16 h_mult_total;
|
||||
mode_flags target_lm;
|
||||
alt_u32 pclk_o_hz;
|
||||
avinput_t avinput;
|
||||
alt_u8 pll_config;
|
||||
// Current configuration
|
||||
avconfig_t cc;
|
||||
} avmode_t;
|
||||
@ -123,6 +96,7 @@ void ui_disp_status(alt_u8 refresh_osd_timer);
|
||||
int load_profile();
|
||||
int save_profile();
|
||||
|
||||
void print_vm_stats();
|
||||
int latency_test();
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (C) 2015-2019 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
// Copyright (C) 2015-2023 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
//
|
||||
// This file is part of Open Source Scan Converter project.
|
||||
//
|
||||
@ -26,7 +26,6 @@
|
||||
|
||||
#define DEFAULT_ON 1
|
||||
|
||||
extern mode_data_t video_modes[], video_modes_default[];
|
||||
extern alt_u8 update_cur_vm;
|
||||
|
||||
// Target configuration
|
||||
@ -39,7 +38,6 @@ const avconfig_t tc_default = {
|
||||
.pm_384p = 1,
|
||||
.pm_480i = 1,
|
||||
.pm_1080i = 1,
|
||||
.tvp_hpll2x = DEFAULT_ON,
|
||||
.sync_vth = DEFAULT_SYNC_VTH,
|
||||
.linelen_tol = DEFAULT_LINELEN_TOL,
|
||||
.vsync_thold = DEFAULT_VSYNC_THOLD,
|
||||
@ -74,7 +72,7 @@ int set_default_avconfig()
|
||||
tc.tx_mode = (IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & HDMITX_MODE_MASK) ? TX_DVI : TX_HDMI_RGB;
|
||||
#endif
|
||||
|
||||
memcpy(video_modes, video_modes_default, VIDEO_MODES_SIZE);
|
||||
set_default_vm_table();
|
||||
update_cur_vm = 1;
|
||||
|
||||
return 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (C) 2015-2019 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
// Copyright (C) 2015-2023 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
//
|
||||
// This file is part of Open Source Scan Converter project.
|
||||
//
|
||||
@ -21,7 +21,7 @@
|
||||
#define AVCONFIG_H_
|
||||
|
||||
#include "alt_types.h"
|
||||
#include "tvp7002.h"
|
||||
#include "sysconfig.h"
|
||||
|
||||
#define SIGNED_NUMVAL_ZERO 128
|
||||
|
||||
@ -72,18 +72,28 @@ typedef enum {
|
||||
AV_LAST = 10
|
||||
} avinput_t;
|
||||
|
||||
typedef struct {
|
||||
alt_u8 r_f_off;
|
||||
alt_u8 g_f_off;
|
||||
alt_u8 b_f_off;
|
||||
alt_u8 r_f_gain;
|
||||
alt_u8 g_f_gain;
|
||||
alt_u8 b_f_gain;
|
||||
alt_u8 c_gain;
|
||||
} __attribute__((packed)) color_setup_t;
|
||||
|
||||
typedef struct {
|
||||
alt_u8 sl_mode;
|
||||
alt_u8 sl_type;
|
||||
alt_u8 sl_hybr_str;
|
||||
alt_u8 sl_method;
|
||||
alt_u8 sl_altern;
|
||||
alt_u8 sl_altiv;
|
||||
alt_u8 sl_str;
|
||||
alt_u8 sl_id;
|
||||
alt_u8 sl_cust_l_str[5];
|
||||
alt_u8 sl_cust_c_str[6];
|
||||
alt_u8 linemult_target;
|
||||
alt_u8 sl_cust_iv_x;
|
||||
alt_u8 sl_cust_iv_y;
|
||||
alt_u8 l2_mode;
|
||||
alt_u8 l3_mode;
|
||||
alt_u8 l4_mode;
|
||||
@ -103,7 +113,6 @@ typedef struct {
|
||||
alt_u8 hdmi_itc;
|
||||
alt_u8 s480p_mode;
|
||||
alt_u8 s400p_mode;
|
||||
alt_u8 tvp_hpll2x;
|
||||
alt_u8 upsample2x;
|
||||
alt_u8 ypbpr_cs;
|
||||
alt_u8 sync_vth;
|
||||
@ -115,13 +124,12 @@ typedef struct {
|
||||
alt_u8 pre_coast;
|
||||
alt_u8 post_coast;
|
||||
alt_u8 full_tx_setup;
|
||||
alt_u8 vga_ilace_fix;
|
||||
alt_u8 av3_alt_rgb;
|
||||
alt_u8 panasonic_hack;
|
||||
alt_u8 reverse_lpf;
|
||||
alt_u8 audio_dw_sampl;
|
||||
alt_u8 audio_swap_lr;
|
||||
alt_u8 audio_gain;
|
||||
alt_u8 audio_mono;
|
||||
alt_u8 default_vic;
|
||||
alt_u8 clamp_offset;
|
||||
alt_u8 alc_h_filter;
|
||||
|
489
software/sys_controller/ossc/video_modes.c
Normal file
489
software/sys_controller/ossc/video_modes.c
Normal file
@ -0,0 +1,489 @@
|
||||
//
|
||||
// Copyright (C) 2015-2023 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
//
|
||||
// This file is part of Open Source Scan Converter project.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "system.h"
|
||||
#include "video_modes.h"
|
||||
#include "av_controller.h"
|
||||
#include "avconfig.h"
|
||||
|
||||
#define VM_OUT_YMULT (vm_conf->y_rpt+1)
|
||||
#define VM_OUT_XMULT (vm_conf->x_rpt+1)
|
||||
#define VM_OUT_PCLKMULT (((vm_conf->x_rpt+1)*(vm_conf->y_rpt+1))/(vm_conf->h_skip+1))
|
||||
|
||||
#include "video_modes_list.c"
|
||||
|
||||
const int num_video_modes_plm = sizeof(video_modes_plm_default)/sizeof(mode_data_t);
|
||||
|
||||
mode_data_t video_modes_plm[sizeof(video_modes_plm_default)/sizeof(mode_data_t)];
|
||||
|
||||
void set_default_vm_table() {
|
||||
memcpy(video_modes_plm, video_modes_plm_default, sizeof(video_modes_plm_default));
|
||||
}
|
||||
|
||||
void vmode_hv_mult(mode_data_t *vmode, uint8_t h_mult, uint8_t v_mult) {
|
||||
uint32_t val, bp_extra;
|
||||
|
||||
val = vmode->timings.h_synclen * h_mult;
|
||||
if (val > H_SYNCLEN_MAX) {
|
||||
vmode->timings.h_synclen = H_SYNCLEN_MAX;
|
||||
bp_extra = val - vmode->timings.h_synclen;
|
||||
} else {
|
||||
vmode->timings.h_synclen = val;
|
||||
bp_extra = 0;
|
||||
}
|
||||
|
||||
val = (vmode->timings.h_backporch * h_mult) + bp_extra;
|
||||
if (val > H_BPORCH_MAX)
|
||||
vmode->timings.h_backporch = H_BPORCH_MAX;
|
||||
else
|
||||
vmode->timings.h_backporch = val;
|
||||
|
||||
val = vmode->timings.h_active * h_mult;
|
||||
if (val > H_ACTIVE_MAX)
|
||||
vmode->timings.h_active = H_ACTIVE_MAX;
|
||||
else
|
||||
vmode->timings.h_active = val;
|
||||
|
||||
vmode->timings.h_total = h_mult * vmode->timings.h_total + ((h_mult * vmode->timings.h_total_adj * 5 + 50) / 100);
|
||||
|
||||
val = vmode->timings.v_synclen * v_mult;
|
||||
if (val > V_SYNCLEN_MAX) {
|
||||
vmode->timings.v_synclen = V_SYNCLEN_MAX;
|
||||
bp_extra = val - vmode->timings.v_synclen;
|
||||
} else {
|
||||
vmode->timings.v_synclen = val;
|
||||
bp_extra = 0;
|
||||
}
|
||||
|
||||
val = (vmode->timings.v_backporch * v_mult) + bp_extra;
|
||||
if (val > V_BPORCH_MAX)
|
||||
vmode->timings.v_backporch = V_BPORCH_MAX;
|
||||
else
|
||||
vmode->timings.v_backporch = val;
|
||||
|
||||
val = vmode->timings.v_active * v_mult;
|
||||
if (val > V_ACTIVE_MAX)
|
||||
vmode->timings.v_active = V_ACTIVE_MAX;
|
||||
else
|
||||
vmode->timings.v_active = val;
|
||||
|
||||
if (vmode->timings.interlaced && ((v_mult % 2) == 0)) {
|
||||
vmode->timings.interlaced = 0;
|
||||
vmode->timings.v_total *= (v_mult / 2);
|
||||
} else {
|
||||
vmode->timings.v_total *= v_mult;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t estimate_dotclk(mode_data_t *vm_in, uint32_t h_hz) {
|
||||
if ((vm_in->type & VIDEO_SDTV) ||
|
||||
(vm_in->type & VIDEO_EDTV))
|
||||
{
|
||||
return h_hz * 858;
|
||||
} else {
|
||||
return vm_in->timings.h_total * h_hz;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t calculate_pclk(uint32_t src_clk_hz, mode_data_t *vm_out, vm_proc_config_t *vm_conf) {
|
||||
uint32_t pclk_hz;
|
||||
|
||||
if (vm_conf->si_pclk_mult > 0) {
|
||||
pclk_hz = vm_conf->si_pclk_mult*src_clk_hz;
|
||||
} else if (vm_conf->si_pclk_mult < 0) {
|
||||
pclk_hz = src_clk_hz/((-1)*vm_conf->si_pclk_mult+1);
|
||||
} else {
|
||||
// Round to kHz but maximize accuracy without using 64-bit division
|
||||
pclk_hz = (((uint32_t)((((uint64_t)vm_out->timings.h_total*vm_out->timings.v_total*vm_out->timings.v_hz_x100)>>vm_out->timings.interlaced)/8)+6250)/12500)*1000;
|
||||
|
||||
// Switch to integer mult if possible
|
||||
if (!vm_conf->framelock) {
|
||||
if ((pclk_hz >= src_clk_hz) && (pclk_hz % src_clk_hz == 0))
|
||||
vm_conf->si_pclk_mult = (pclk_hz/src_clk_hz);
|
||||
else if ((pclk_hz < src_clk_hz) && (src_clk_hz % pclk_hz == 0))
|
||||
vm_conf->si_pclk_mult = (-1)*((src_clk_hz/pclk_hz)-1);
|
||||
}
|
||||
}
|
||||
|
||||
return pclk_hz;
|
||||
}
|
||||
|
||||
int get_pure_lm_mode(avconfig_t *cc, mode_data_t *vm_in, mode_data_t *vm_out, vm_proc_config_t *vm_conf)
|
||||
{
|
||||
int i, diff_lines, diff_v_hz_x100, mindiff_id=0, mindiff_lines=1000, mindiff_v_hz_x100=10000;
|
||||
mode_data_t *mode_preset;
|
||||
mode_flags valid_lm[] = { MODE_PT, (MODE_L2 | (MODE_L2<<cc->l2_mode)), (MODE_L3_GEN_16_9<<cc->l3_mode), (MODE_L4_GEN_4_3<<cc->l4_mode), (MODE_L5_GEN_4_3<<cc->l5_mode) };
|
||||
mode_flags target_lm, mindiff_lm;
|
||||
uint8_t pt_only = 0;
|
||||
uint8_t upsample2x = cc->upsample2x;
|
||||
|
||||
// one for each video_group
|
||||
uint8_t* group_ptr[] = { &pt_only, &cc->pm_240p, &cc->pm_240p, &cc->pm_384p, &cc->pm_480i, &cc->pm_480i, &cc->pm_480p, &cc->pm_480p, &pt_only, &cc->pm_1080i, &pt_only };
|
||||
|
||||
for (i=0; i<num_video_modes_plm; i++) {
|
||||
mode_preset = &video_modes_plm[i];
|
||||
|
||||
switch (mode_preset->group) {
|
||||
case GROUP_384P:
|
||||
//fixed Line2x/3x mode for 240x360p/400p
|
||||
valid_lm[2] = MODE_L3_GEN_16_9;
|
||||
valid_lm[3] = MODE_L2_240x360;
|
||||
valid_lm[4] = MODE_L3_240x360;
|
||||
if ((!vm_in->timings.h_total) && (mode_preset->timings.v_total == 449)) {
|
||||
if (!strncmp(mode_preset->name, "720x400_70", 10)) {
|
||||
if (cc->s400p_mode == 0)
|
||||
continue;
|
||||
} else if (!strncmp(mode_preset->name, "640x400_70", 10)) {
|
||||
if (cc->s400p_mode == 1)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GROUP_480I:
|
||||
case GROUP_576I:
|
||||
//fixed Line3x/4x mode for 480i
|
||||
valid_lm[2] = MODE_L3_GEN_16_9;
|
||||
valid_lm[3] = MODE_L4_GEN_4_3;
|
||||
break;
|
||||
case GROUP_480P:
|
||||
if (mode_preset->vic == HDMI_480p60) {
|
||||
switch (cc->s480p_mode) {
|
||||
case 0: // Auto
|
||||
if (vm_in->timings.h_synclen > 82)
|
||||
continue;
|
||||
break;
|
||||
case 1: // DTV 480p
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
} else if (mode_preset->vic == HDMI_640x480p60) {
|
||||
switch (cc->s480p_mode) {
|
||||
case 0: // Auto
|
||||
case 2: // VESA 640x480@60
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
target_lm = valid_lm[*group_ptr[mode_preset->group]];
|
||||
|
||||
if ((target_lm & mode_preset->flags) &&
|
||||
(vm_in->timings.interlaced == mode_preset->timings.interlaced))
|
||||
{
|
||||
diff_lines = abs(vm_in->timings.v_total - mode_preset->timings.v_total);
|
||||
diff_v_hz_x100 = abs(vm_in->timings.v_hz_x100 - mode_preset->timings.v_hz_x100);
|
||||
|
||||
if ((diff_lines < mindiff_lines) || ((mode_preset->group >= GROUP_720P) && (diff_lines == mindiff_lines) && (diff_v_hz_x100 < mindiff_v_hz_x100))) {
|
||||
mindiff_id = i;
|
||||
mindiff_lines = diff_lines;
|
||||
mindiff_v_hz_x100 = diff_v_hz_x100;
|
||||
mindiff_lm = target_lm;
|
||||
} else if ((mindiff_lines <= 2) && (diff_lines > mindiff_lines)) {
|
||||
// Break out if suitable mode already found
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mindiff_lines >= 110)
|
||||
return -1;
|
||||
|
||||
mode_preset = &video_modes_plm[mindiff_id];
|
||||
|
||||
vm_in->timings.h_active = mode_preset->timings.h_active;
|
||||
vm_in->timings.v_active = mode_preset->timings.v_active;
|
||||
vm_in->timings.h_synclen = mode_preset->timings.h_synclen;
|
||||
vm_in->timings.v_synclen = mode_preset->timings.v_synclen;
|
||||
vm_in->timings.h_backporch = mode_preset->timings.h_backporch;
|
||||
vm_in->timings.v_backporch = mode_preset->timings.v_backporch;
|
||||
vm_in->timings.h_total = mode_preset->timings.h_total;
|
||||
vm_in->timings.h_total_adj = mode_preset->timings.h_total_adj;
|
||||
vm_in->sampler_phase = mode_preset->sampler_phase;
|
||||
vm_in->type = mode_preset->type;
|
||||
vm_in->group = mode_preset->group;
|
||||
vm_in->vic = mode_preset->vic;
|
||||
strncpy(vm_in->name, mode_preset->name, 10);
|
||||
|
||||
memcpy(vm_out, vm_in, sizeof(mode_data_t));
|
||||
vm_out->vic = HDMI_Unknown;
|
||||
|
||||
memset(vm_conf, 0, sizeof(vm_proc_config_t));
|
||||
vm_conf->si_pclk_mult = 1;
|
||||
|
||||
mindiff_lm &= mode_preset->flags; //ensure L2 mode uniqueness
|
||||
|
||||
switch (mindiff_lm) {
|
||||
case MODE_PT:
|
||||
vm_out->vic = vm_in->vic;
|
||||
|
||||
// multiply horizontal resolution if necessary to fulfill min. 25MHz TMDS clock requirement. Tweak infoframe pixel repetition indicator later to make sink treat it as original resolution.
|
||||
while ((((vm_out->timings.v_hz_x100*vm_out->timings.v_total)/100)*vm_out->timings.h_total*(vm_conf->h_skip+1))>>vm_out->timings.interlaced < 25000000UL) {
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 2*(vm_conf->h_skip+1)-1;
|
||||
}
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L2:
|
||||
vm_conf->y_rpt = 1;
|
||||
|
||||
// Upsample / pixel-repeat horizontal resolution of 384p/480p/960i modes
|
||||
if ((mode_preset->group == GROUP_384P) || (mode_preset->group == GROUP_480P) || (mode_preset->group == GROUP_576P) || ((mode_preset->group == GROUP_1080I) && (mode_preset->timings.h_total < 1200))) {
|
||||
if (upsample2x) {
|
||||
vmode_hv_mult(vm_in, 2, 1);
|
||||
vmode_hv_mult(vm_out, 2, VM_OUT_YMULT);
|
||||
} else {
|
||||
vm_conf->x_rpt = 1;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
}
|
||||
} else {
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
}
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L2_512_COL:
|
||||
vm_conf->y_rpt = 1;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 1;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L2_384_COL:
|
||||
case MODE_L2_320_COL:
|
||||
vm_conf->y_rpt = 1;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 1;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L2_256_COL:
|
||||
vm_conf->y_rpt = 1;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 2;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
vm_conf->x_rpt -= cc->ar_256col;
|
||||
break;
|
||||
case MODE_L2_240x360:
|
||||
vm_conf->y_rpt = 1;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 4;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L3_GEN_16_9:
|
||||
vm_conf->y_rpt = 2;
|
||||
|
||||
// Upsample / pixel-repeat horizontal resolution of 480i mode
|
||||
if ((mode_preset->group == GROUP_480I) || (mode_preset->group == GROUP_576I)) {
|
||||
if (upsample2x) {
|
||||
vmode_hv_mult(vm_in, 2, 1);
|
||||
vmode_hv_mult(vm_out, 2, VM_OUT_YMULT);
|
||||
} else {
|
||||
vm_conf->x_rpt = 1;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
}
|
||||
} else {
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
}
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L3_GEN_4_3:
|
||||
vm_conf->y_rpt = 2;
|
||||
vm_conf->x_size = vm_out->timings.h_active;
|
||||
vm_out->timings.h_synclen /= 3;
|
||||
vm_out->timings.h_backporch /= 3;
|
||||
vm_out->timings.h_active /= 3;
|
||||
vm_conf->x_offset = vm_out->timings.h_active/2;
|
||||
vm_out->timings.h_total /= 3;
|
||||
vm_out->timings.h_total_adj = 0;
|
||||
vmode_hv_mult(vm_out, 4, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = 4;
|
||||
break;
|
||||
case MODE_L3_512_COL:
|
||||
vm_conf->y_rpt = 2;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 1;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L3_384_COL:
|
||||
vm_conf->y_rpt = 2;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 2;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L3_320_COL:
|
||||
vm_conf->y_rpt = 2;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 3;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
vm_conf->x_rpt = 2;
|
||||
break;
|
||||
case MODE_L3_256_COL:
|
||||
vm_conf->y_rpt = 2;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 4;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
vm_conf->x_rpt = cc->ar_256col ? 2 : 3;
|
||||
break;
|
||||
case MODE_L3_240x360:
|
||||
vm_conf->y_rpt = 2;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 6;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
//cm.hsync_cut = 13;
|
||||
break;
|
||||
case MODE_L4_GEN_4_3:
|
||||
vm_conf->y_rpt = 3;
|
||||
|
||||
// Upsample / pixel-repeat horizontal resolution of 480i mode
|
||||
if ((mode_preset->group == GROUP_480I) || (mode_preset->group == GROUP_576I)) {
|
||||
if (upsample2x) {
|
||||
vmode_hv_mult(vm_in, 2, 1);
|
||||
vmode_hv_mult(vm_out, 2, VM_OUT_YMULT);
|
||||
} else {
|
||||
vm_conf->x_rpt = 1;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
}
|
||||
} else {
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
}
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L4_512_COL:
|
||||
vm_conf->y_rpt = 3;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 1;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L4_384_COL:
|
||||
vm_conf->y_rpt = 3;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 2;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L4_320_COL:
|
||||
vm_conf->y_rpt = 3;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 3;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L4_256_COL:
|
||||
vm_conf->y_rpt = 3;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 4;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
vm_conf->x_rpt -= cc->ar_256col;
|
||||
break;
|
||||
case MODE_L5_GEN_4_3:
|
||||
vm_conf->y_rpt = 4;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
break;
|
||||
case MODE_L5_512_COL:
|
||||
vm_conf->y_rpt = 4;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 2;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
//cm.hsync_cut = 40;
|
||||
break;
|
||||
case MODE_L5_384_COL:
|
||||
vm_conf->y_rpt = 4;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 3;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
//cm.hsync_cut = 30;
|
||||
break;
|
||||
case MODE_L5_320_COL:
|
||||
vm_conf->y_rpt = 4;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 4;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
//cm.hsync_cut = 24;
|
||||
break;
|
||||
case MODE_L5_256_COL:
|
||||
vm_conf->y_rpt = 4;
|
||||
vm_conf->x_rpt = vm_conf->h_skip = 5;
|
||||
vmode_hv_mult(vm_out, VM_OUT_XMULT, VM_OUT_YMULT);
|
||||
vm_conf->si_pclk_mult = VM_OUT_PCLKMULT;
|
||||
vm_conf->x_rpt -= cc->ar_256col;
|
||||
//cm.hsync_cut = 20;
|
||||
break;
|
||||
default:
|
||||
printf("WARNING: invalid mindiff_lm\n");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
sniprintf(vm_out->name, 10, "%s x%u", vm_in->name, vm_conf->y_rpt+1);
|
||||
|
||||
if (vm_conf->x_size == 0)
|
||||
vm_conf->x_size = vm_in->timings.h_active*(vm_conf->x_rpt+1);
|
||||
if (vm_conf->y_size == 0)
|
||||
vm_conf->y_size = vm_out->timings.v_active;
|
||||
|
||||
vm_conf->x_offset = ((vm_out->timings.h_active-vm_conf->x_size)/2);
|
||||
vm_conf->x_start_lb = (vm_conf->x_offset >= 0) ? 0 : (-vm_conf->x_offset / (vm_conf->x_rpt+1));
|
||||
|
||||
// Line5x format
|
||||
if (vm_conf->y_rpt == 4) {
|
||||
// adjust output width to 1920
|
||||
if (cc->l5_fmt != 1) {
|
||||
vm_conf->x_offset = (1920-vm_conf->x_size)/2;
|
||||
vm_out->timings.h_synclen = (vm_out->timings.h_total - 1920)/4;
|
||||
vm_out->timings.h_backporch = (vm_out->timings.h_total - 1920)/2;
|
||||
vm_out->timings.h_active = 1920;
|
||||
}
|
||||
|
||||
// adjust output height to 1080
|
||||
if (cc->l5_fmt == 0) {
|
||||
vm_conf->y_start_lb = (vm_out->timings.v_active-1080)/10;
|
||||
vm_out->timings.v_backporch += 5*vm_conf->y_start_lb;
|
||||
vm_out->timings.v_active = 1080;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LM_EMIF_EXTRA_DELAY
|
||||
vm_conf->framesync_line = ((vm_out->timings.v_total>>vm_out->timings.interlaced)-(1+vm_out->timings.interlaced)*(vm_conf->y_rpt+1));
|
||||
#else
|
||||
//vm_conf->framesync_line = vm_in->timings.interlaced ? ((vm_out->timings.v_total>>vm_out->timings.interlaced)-(vm_conf->y_rpt+1)) : 0;
|
||||
vm_conf->framesync_line = 0;
|
||||
#endif
|
||||
vm_conf->framelock = 1;
|
||||
|
||||
if (vm_out->vic == HDMI_Unknown)
|
||||
vm_out->vic = cc->default_vic;
|
||||
|
||||
return mindiff_id;
|
||||
}
|
||||
|
||||
int get_vmode(vmode_t vmode_id, mode_data_t *vm_in, mode_data_t *vm_out, vm_proc_config_t *vm_conf)
|
||||
{
|
||||
memset(vm_conf, 0, sizeof(vm_proc_config_t));
|
||||
memset(vm_in, 0, sizeof(mode_data_t));
|
||||
memcpy(vm_out, &video_modes_plm[vmode_id], sizeof(mode_data_t));
|
||||
|
||||
return 0;
|
||||
}
|
173
software/sys_controller/ossc/video_modes.h
Normal file
173
software/sys_controller/ossc/video_modes.h
Normal file
@ -0,0 +1,173 @@
|
||||
//
|
||||
// Copyright (C) 2015-2023 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
//
|
||||
// This file is part of Open Source Scan Converter project.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#ifndef VIDEO_MODES_H_
|
||||
#define VIDEO_MODES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sysconfig.h"
|
||||
#include "avconfig.h"
|
||||
#include "it6613_sys.h"
|
||||
|
||||
#define DEF_PHASE 0x10
|
||||
|
||||
#define H_TOTAL_MIN 300
|
||||
#define H_TOTAL_MAX 2800
|
||||
#define H_TOTAL_ADJ_MAX 19
|
||||
#define H_SYNCLEN_MIN 10
|
||||
#define H_SYNCLEN_MAX 255
|
||||
#define H_BPORCH_MIN 0
|
||||
#define H_BPORCH_MAX 511
|
||||
#define H_ACTIVE_MIN 200
|
||||
#define H_ACTIVE_MAX 2560
|
||||
#define H_ACTIVE_SMP_MAX 2048
|
||||
#define V_SYNCLEN_MIN 1
|
||||
#define V_SYNCLEN_MAX 15
|
||||
#define V_BPORCH_MIN 0
|
||||
#define V_BPORCH_MAX 511
|
||||
#define V_ACTIVE_MIN 160
|
||||
#define V_ACTIVE_MAX 1440
|
||||
|
||||
typedef enum {
|
||||
FORMAT_RGBS = 0,
|
||||
FORMAT_RGBHV = 1,
|
||||
FORMAT_RGsB = 2,
|
||||
FORMAT_YPbPr = 3
|
||||
} video_format;
|
||||
|
||||
typedef enum {
|
||||
VIDEO_SDTV = (1<<0),
|
||||
VIDEO_EDTV = (1<<1),
|
||||
VIDEO_HDTV = (1<<2),
|
||||
VIDEO_PC = (1<<3),
|
||||
} video_type;
|
||||
|
||||
typedef enum {
|
||||
GROUP_NONE = 0,
|
||||
GROUP_240P = 1,
|
||||
GROUP_288P = 2,
|
||||
GROUP_384P = 3,
|
||||
GROUP_480I = 4,
|
||||
GROUP_576I = 5,
|
||||
GROUP_480P = 6,
|
||||
GROUP_576P = 7,
|
||||
GROUP_720P = 8,
|
||||
GROUP_1080I = 9,
|
||||
GROUP_1080P = 10,
|
||||
} video_group;
|
||||
|
||||
typedef enum {
|
||||
MODE_INTERLACED = (1<<0), //deprecated
|
||||
MODE_CRT = (1<<1),
|
||||
//at least one of the flags below must be set for each P-LM mode
|
||||
MODE_PT = (1<<2),
|
||||
MODE_L2 = (1<<3),
|
||||
MODE_L2_512_COL = (1<<4),
|
||||
MODE_L2_384_COL = (1<<5),
|
||||
MODE_L2_320_COL = (1<<6),
|
||||
MODE_L2_256_COL = (1<<7),
|
||||
MODE_L2_240x360 = (1<<8),
|
||||
MODE_L3_GEN_16_9 = (1<<9),
|
||||
MODE_L3_GEN_4_3 = (1<<10),
|
||||
MODE_L3_512_COL = (1<<11),
|
||||
MODE_L3_384_COL = (1<<12),
|
||||
MODE_L3_320_COL = (1<<13),
|
||||
MODE_L3_256_COL = (1<<14),
|
||||
MODE_L3_240x360 = (1<<15),
|
||||
MODE_L4_GEN_4_3 = (1<<16),
|
||||
MODE_L4_512_COL = (1<<17),
|
||||
MODE_L4_384_COL = (1<<18),
|
||||
MODE_L4_320_COL = (1<<19),
|
||||
MODE_L4_256_COL = (1<<20),
|
||||
MODE_L5_GEN_4_3 = (1<<21),
|
||||
MODE_L5_512_COL = (1<<22),
|
||||
MODE_L5_384_COL = (1<<23),
|
||||
MODE_L5_320_COL = (1<<24),
|
||||
MODE_L5_256_COL = (1<<25),
|
||||
} mode_flags;
|
||||
|
||||
typedef enum {
|
||||
VMODE_480p = 24,
|
||||
} vmode_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t h_active;
|
||||
uint16_t v_active;
|
||||
uint16_t v_hz_x100;
|
||||
uint16_t h_total;
|
||||
uint8_t h_total_adj;
|
||||
uint16_t v_total;
|
||||
uint16_t h_backporch;
|
||||
uint16_t v_backporch;
|
||||
uint16_t h_synclen;
|
||||
uint8_t v_synclen;
|
||||
uint8_t interlaced;
|
||||
} sync_timings_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t h;
|
||||
uint8_t v;
|
||||
} aspect_ratio_t;
|
||||
|
||||
typedef enum {
|
||||
TX_1X = 0,
|
||||
TX_2X = 1,
|
||||
TX_4X = 2
|
||||
} HDMI_pixelrep_t;
|
||||
|
||||
typedef struct {
|
||||
char name[10];
|
||||
HDMI_Video_Type vic;
|
||||
sync_timings_t timings;
|
||||
uint8_t sampler_phase;
|
||||
aspect_ratio_t ar;
|
||||
video_type type;
|
||||
video_group group;
|
||||
mode_flags flags;
|
||||
} mode_data_t;
|
||||
|
||||
typedef struct {
|
||||
int8_t x_rpt;
|
||||
int8_t y_rpt;
|
||||
uint8_t h_skip;
|
||||
uint8_t h_sample_sel;
|
||||
int16_t x_offset;
|
||||
int16_t y_offset;
|
||||
uint16_t x_size;
|
||||
uint16_t y_size;
|
||||
uint16_t framesync_line;
|
||||
uint8_t x_start_lb;
|
||||
int8_t y_start_lb;
|
||||
uint8_t framelock;
|
||||
// for generation from 27MHz clock
|
||||
int8_t si_pclk_mult;
|
||||
} vm_proc_config_t;
|
||||
|
||||
|
||||
void set_default_vm_table();
|
||||
|
||||
uint32_t estimate_dotclk(mode_data_t *vm_in, uint32_t h_hz);
|
||||
|
||||
uint32_t calculate_pclk(uint32_t src_clk_hz, mode_data_t *vm_out, vm_proc_config_t *vm_conf);
|
||||
|
||||
int get_pure_lm_mode(avconfig_t *cc, mode_data_t *vm_in, mode_data_t *vm_out, vm_proc_config_t *vm_conf);
|
||||
|
||||
int get_vmode(vmode_t vmode_id, mode_data_t *vm_in, mode_data_t *vm_out, vm_proc_config_t *vm_conf);
|
||||
|
||||
#endif /* VIDEO_MODES_H_ */
|
84
software/sys_controller/ossc/video_modes_list.c
Normal file
84
software/sys_controller/ossc/video_modes_list.c
Normal file
@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright (C) 2020-2023 Markus Hiienkari <mhiienka@niksula.hut.fi>
|
||||
//
|
||||
// This file is part of Open Source Scan Converter project.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
/* Pure LM modes */
|
||||
#ifdef VM_STATIC_INCLUDE
|
||||
static
|
||||
#endif
|
||||
const mode_data_t video_modes_plm_default[] = {
|
||||
/* 240p modes */
|
||||
{ "1600x240", HDMI_Unknown, {1600, 240, 6000, 2046, 0, 262, 202, 15, 150, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_240P, (MODE_L5_GEN_4_3), },
|
||||
{ "1280x240", HDMI_Unknown, {1280, 240, 6000, 1560, 0, 262, 170, 15, 72, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_240P, (MODE_L3_GEN_16_9 | MODE_L4_GEN_4_3), },
|
||||
{ "960x240", HDMI_Unknown, { 960, 240, 6000, 1170, 0, 262, 128, 15, 54, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_240P, (MODE_L3_GEN_4_3), },
|
||||
{ "512x240", HDMI_Unknown, { 512, 240, 6000, 682, 0, 262, 77, 14, 50, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_240P, (MODE_L2_512_COL | MODE_L3_512_COL | MODE_L4_512_COL | MODE_L5_512_COL), },
|
||||
{ "384x240", HDMI_Unknown, { 384, 240, 6000, 512, 0, 262, 59, 14, 37, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_240P, (MODE_L2_384_COL | MODE_L3_384_COL | MODE_L4_384_COL | MODE_L5_384_COL), },
|
||||
{ "320x240", HDMI_Unknown, { 320, 240, 6000, 426, 0, 262, 49, 14, 31, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_240P, (MODE_L2_320_COL | MODE_L3_320_COL | MODE_L4_320_COL | MODE_L5_320_COL), },
|
||||
{ "256x240", HDMI_Unknown, { 256, 240, 6000, 341, 0, 262, 39, 14, 25, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_240P, (MODE_L2_256_COL | MODE_L3_256_COL | MODE_L4_256_COL | MODE_L5_256_COL), },
|
||||
{ "240p", HDMI_240p60, { 720, 240, 6005, 858, 0, 262, 57, 15, 62, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_240P, (MODE_PT | MODE_L2), },
|
||||
/* 288p modes */
|
||||
{ "1600x240L", HDMI_Unknown, {1600, 240, 5000, 2046, 0, 312, 202, 43, 150, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_288P, (MODE_L5_GEN_4_3), },
|
||||
{ "1280x288", HDMI_Unknown, {1280, 288, 5000, 1560, 0, 312, 170, 19, 72, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_288P, (MODE_L3_GEN_16_9 | MODE_L4_GEN_4_3), },
|
||||
{ "960x288", HDMI_Unknown, { 960, 288, 5000, 1170, 0, 312, 128, 19, 54, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_288P, (MODE_L3_GEN_4_3), },
|
||||
{ "512x240LB", HDMI_Unknown, { 512, 240, 5000, 682, 0, 312, 77, 41, 50, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_288P, (MODE_L2_512_COL | MODE_L3_512_COL | MODE_L4_512_COL | MODE_L5_512_COL), },
|
||||
{ "384x240LB", HDMI_Unknown, { 384, 240, 5000, 512, 0, 312, 59, 41, 37, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_288P, (MODE_L2_384_COL | MODE_L3_384_COL | MODE_L4_384_COL | MODE_L5_384_COL), },
|
||||
{ "320x240LB", HDMI_Unknown, { 320, 240, 5000, 426, 0, 312, 49, 41, 31, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_288P, (MODE_L2_320_COL | MODE_L3_320_COL | MODE_L4_320_COL | MODE_L5_320_COL), },
|
||||
{ "256x240LB", HDMI_Unknown, { 256, 240, 5000, 341, 0, 312, 39, 41, 25, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_288P, (MODE_L2_256_COL | MODE_L3_256_COL | MODE_L4_256_COL | MODE_L5_256_COL), },
|
||||
{ "288p", HDMI_288p50, { 720, 288, 5008, 864, 0, 312, 69, 19, 63, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_288P, (MODE_PT | MODE_L2), },
|
||||
/* 360p: GBI */
|
||||
{ "480x360", HDMI_Unknown, { 480, 360, 6000, 600, 0, 375, 63, 10, 38, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_EDTV, GROUP_384P, (MODE_PT | MODE_L2), },
|
||||
{ "240x360", HDMI_Unknown, { 256, 360, 6000, 300, 0, 375, 24, 10, 18, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_EDTV, GROUP_384P, (MODE_L2_240x360 | MODE_L3_240x360), },
|
||||
/* 384p: Sega Model 2 */
|
||||
{ "384p", HDMI_Unknown, { 496, 384, 5500, 640, 0, 423, 50, 29, 62, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_EDTV, GROUP_384P, (MODE_PT | MODE_L2), },
|
||||
/* 400p line3x */
|
||||
{ "1600x400", HDMI_Unknown, {1600, 400, 7000, 2000, 0, 449, 120, 34, 240, 2, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_384P, (MODE_L3_GEN_16_9), },
|
||||
/* 720x400@70Hz, VGA Mode 3+/7+ */
|
||||
{ "720x400_70", HDMI_Unknown, { 720, 400, 7000, 900, 0, 449, 64, 34, 96, 2, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_384P, (MODE_PT | MODE_L2), },
|
||||
/* 640x400@70Hz, VGA Mode 13h */
|
||||
{ "640x400_70", HDMI_Unknown, { 640, 400, 7000, 800, 0, 449, 48, 34, 96, 2, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_384P, (MODE_PT | MODE_L2), },
|
||||
/* 384p: X68k @ 24kHz */
|
||||
{ "640x384", HDMI_Unknown, { 640, 384, 5500, 800, 0, 492, 48, 63, 96, 2, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_384P, (MODE_PT | MODE_L2), },
|
||||
/* ~525-line modes */
|
||||
{ "480i", HDMI_480i60, { 720, 240, 5994, 858, 0, 525, 57, 15, 62, 3, 1}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_480I, (MODE_PT | MODE_L2 | MODE_L3_GEN_16_9 | MODE_L4_GEN_4_3), },
|
||||
{ "480p", HDMI_480p60, { 720, 480, 5994, 858, 0, 525, 60, 30, 62, 6, 0}, DEF_PHASE, { 4, 3}, VIDEO_EDTV, GROUP_480P, (MODE_PT | MODE_L2), },
|
||||
{ "640x480_60", HDMI_640x480p60, { 640, 480, 6000, 800, 0, 525, 48, 33, 96, 2, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_480P, (MODE_PT | MODE_L2), },
|
||||
/* 480p PSP in-game */ \
|
||||
{ "480x272", HDMI_480p60_16x9, { 480, 272, 6000, 858, 0, 525, 177,134, 62, 6, 0}, DEF_PHASE, {16, 9}, VIDEO_EDTV, GROUP_480P, (MODE_PT | MODE_L2) }, \
|
||||
/* X68k @ 31kHz */
|
||||
{ "640x512", HDMI_Unknown, { 640, 512, 6000, 800, 0, 568, 48, 34, 96, 6, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_480P, (MODE_PT | MODE_L2), },
|
||||
/* ~625-line modes */
|
||||
{ "576i", HDMI_576i50, { 720, 288, 5000, 864, 0, 625, 69, 19, 63, 3, 1}, DEF_PHASE, { 4, 3}, VIDEO_SDTV, GROUP_576I, (MODE_PT | MODE_L2 | MODE_L3_GEN_16_9 | MODE_L4_GEN_4_3), },
|
||||
{ "576p", HDMI_576p50, { 720, 576, 5000, 864, 0, 625, 68, 39, 64, 5, 0}, DEF_PHASE, { 4, 3}, VIDEO_EDTV, GROUP_576P, (MODE_PT | MODE_L2), },
|
||||
{ "800x600_60", HDMI_Unknown, { 800, 600, 6000, 1056, 0, 628, 88, 23, 128, 4, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_NONE, MODE_PT, },
|
||||
/* CEA 720p modes */
|
||||
{ "720p_50", HDMI_720p50, {1280, 720, 5000, 1980, 0, 750, 220, 20, 40, 5, 0}, DEF_PHASE, {16, 9}, (VIDEO_HDTV | VIDEO_PC), GROUP_720P, MODE_PT, },
|
||||
{ "720p_60", HDMI_720p60, {1280, 720, 6000, 1650, 0, 750, 220, 20, 40, 5, 0}, DEF_PHASE, {16, 9}, (VIDEO_HDTV | VIDEO_PC), GROUP_720P, MODE_PT, },
|
||||
/* VESA XGA,1280x960 and SXGA modes */
|
||||
{ "1024x768", HDMI_Unknown, {1024, 768, 6000, 1344, 0, 806, 160, 29, 136, 6, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_NONE, MODE_PT, },
|
||||
{ "1280x960", HDMI_Unknown, {1280, 960, 6000, 1800, 0, 1000, 312, 36, 112, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_NONE, MODE_PT, },
|
||||
{ "1280x1024", HDMI_Unknown, {1280, 1024, 6000, 1688, 0, 1066, 248, 38, 112, 3, 0}, DEF_PHASE, { 5, 4}, VIDEO_PC, GROUP_NONE, MODE_PT, },
|
||||
/* PS2 GSM 960i mode */
|
||||
{ "640x960i", HDMI_Unknown, { 640, 480, 6000, 800, 0, 1050, 48, 33, 96, 2, 1}, DEF_PHASE, { 4, 3}, VIDEO_EDTV, GROUP_1080I, (MODE_PT | MODE_L2), },
|
||||
/* CEA 1080i/p modes */
|
||||
{ "1080i_50", HDMI_1080i50, {1920, 540, 5000, 2640, 0, 1125, 148, 15, 44, 5, 1}, DEF_PHASE, {16, 9}, (VIDEO_HDTV | VIDEO_PC), GROUP_1080I, (MODE_PT | MODE_L2), },
|
||||
{ "1080i_60", HDMI_1080i60, {1920, 540, 6000, 2200, 0, 1125, 148, 15, 44, 5, 1}, DEF_PHASE, {16, 9}, (VIDEO_HDTV | VIDEO_PC), GROUP_1080I, (MODE_PT | MODE_L2), },
|
||||
{ "1080p_50", HDMI_1080p50, {1920, 1080, 5000, 2640, 0, 1125, 148, 36, 44, 5, 0}, DEF_PHASE, {16, 9}, (VIDEO_HDTV | VIDEO_PC), GROUP_1080P, MODE_PT, },
|
||||
{ "1080p_60", HDMI_1080p60, {1920, 1080, 6000, 2200, 0, 1125, 148, 36, 44, 5, 0}, DEF_PHASE, {16, 9}, (VIDEO_HDTV | VIDEO_PC), GROUP_1080P, MODE_PT, },
|
||||
/* VESA UXGA mode */
|
||||
{ "1600x1200", HDMI_Unknown, {1600, 1200, 6000, 2160, 0, 1250, 304, 46, 192, 3, 0}, DEF_PHASE, { 4, 3}, VIDEO_PC, GROUP_NONE, MODE_PT, },
|
||||
};
|
Loading…
Reference in New Issue
Block a user