From a332a3fce52276663fc4130652752617a78b37ad Mon Sep 17 00:00:00 2001 From: borti4938 Date: Sun, 22 May 2016 20:14:16 +0200 Subject: [PATCH] resort software code database [WIP] - split av_controller.c into several sub-files - WorkInProgress = still needs refactoring --- software/sys_controller/Makefile | 9 +- software/sys_controller/av_controller.c | 1472 ------------------ software/sys_controller/main.c | 251 +++ software/sys_controller/ossc/av_controller.c | 419 +++++ software/sys_controller/ossc/av_controller.h | 91 ++ software/sys_controller/ossc/cfg.c | 39 + software/sys_controller/ossc/cfg.h | 66 + software/sys_controller/ossc/controls.c | 126 ++ software/sys_controller/ossc/controls.h | 46 + software/sys_controller/ossc/fw_version.h | 28 + software/sys_controller/ossc/memory.c | 436 ++++++ software/sys_controller/ossc/memory.h | 81 + software/sys_controller/ossc/menu.c | 292 ++++ software/sys_controller/ossc/menu.h | 25 + software/sys_controller/tvp7002/tvp7002.c | 17 +- software/sys_controller/tvp7002/tvp7002.h | 16 +- 16 files changed, 1924 insertions(+), 1490 deletions(-) delete mode 100755 software/sys_controller/av_controller.c create mode 100644 software/sys_controller/main.c create mode 100755 software/sys_controller/ossc/av_controller.c create mode 100644 software/sys_controller/ossc/av_controller.h create mode 100644 software/sys_controller/ossc/cfg.c create mode 100644 software/sys_controller/ossc/cfg.h create mode 100644 software/sys_controller/ossc/controls.c create mode 100644 software/sys_controller/ossc/controls.h create mode 100644 software/sys_controller/ossc/fw_version.h create mode 100644 software/sys_controller/ossc/memory.c create mode 100644 software/sys_controller/ossc/memory.h create mode 100644 software/sys_controller/ossc/menu.c create mode 100644 software/sys_controller/ossc/menu.h diff --git a/software/sys_controller/Makefile b/software/sys_controller/Makefile index 7f85a7c..c0e12b0 100644 --- a/software/sys_controller/Makefile +++ b/software/sys_controller/Makefile @@ -142,17 +142,22 @@ ACDS_VERSION := 14.1 ELF := sys_controller.elf # Paths to C, C++, and assembly source files. -C_SRCS += av_controller.c C_SRCS += it6613/EDID.c C_SRCS += it6613/HDMI_TX.c C_SRCS += it6613/hdmitx_nios2.c C_SRCS += it6613/it6613.c C_SRCS += it6613/it6613_drv.c -C_SRCS += it6613/it6613_sys.c C_SRCS += tvp7002/tvp7002.c C_SRCS += tvp7002/video_modes.c C_SRCS += ths7353/ths7353.c C_SRCS += spi_charlcd/lcd.c +C_SRCS += ossc/memory.c +C_SRCS += it6613/it6613_sys.c +C_SRCS += main.c +C_SRCS += ossc/av_controller.c +C_SRCS += ossc/controls.c +C_SRCS += ossc/menu.c +C_SRCS += ossc/cfg.c CXX_SRCS := ASM_SRCS := diff --git a/software/sys_controller/av_controller.c b/software/sys_controller/av_controller.c deleted file mode 100755 index fc1a244..0000000 --- a/software/sys_controller/av_controller.c +++ /dev/null @@ -1,1472 +0,0 @@ -// -// Copyright (C) 2015-2016 Markus Hiienkari -// -// 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 . -// - -#include -#include -#include "system.h" -#include "string.h" -#include "altera_avalon_pio_regs.h" -#include "Altera_UP_SD_Card_Avalon_Interface_mod.h" -#include "altera_epcq_controller_mod.h" -#include "i2c_opencores.h" -#include "tvp7002.h" -#include "ths7353.h" -#include "video_modes.h" -#include "lcd.h" -#include "sysconfig.h" -#include "it6613.h" -#include "it6613_sys.h" -#include "HDMI_TX.h" -#include "hdmitx.h" -#include "ci_crc.h" - -alt_u8 fw_ver_major = 0; -alt_u8 fw_ver_minor = 69; -#define FW_UPDATE_RETRIES 3 - -#define LINECNT_THOLD 1 -#define STABLE_THOLD 1 -#define MIN_LINES_PROGRESSIVE 200 -#define MIN_LINES_INTERLACED 400 -#define SYNC_LOSS_THOLD 5 -#define STATUS_TIMEOUT 10000 - -#define MAINLOOP_SLEEP_US 10000 - -#define SCANLINESTR_MAX 15 -#define HV_MASK_MAX 63 -#define L3_MODE_MAX 3 -#define S480P_MODE_MAX 2 -#define SL_MODE_MAX 2 -#define SYNC_LPF_MAX 3 -#define VIDEO_LPF_MAX 5 -#define SAMPLER_PHASE_MIN -16 -#define SAMPLER_PHASE_MAX 15 -#define SYNC_THOLD_MIN -11 -#define SYNC_THOLD_MAX 20 -#define PLL_COAST_MIN 0 -#define PLL_COAST_MAX 5 - -#define DEFAULT_PRE_COAST 1 -#define DEFAULT_POST_COAST 0 - -#define RC_MASK 0x0000ffff -#define PB_MASK 0x00030000 -#define PB0_BIT 0x00010000 -#define PB1_BIT 0x00020000 -#define HDMITX_MODE_MASK 0x00040000 - -static const char *rc_keydesc[] = { "1", "2", "3", "MENU", "BACK", "UP", "DOWN", "LEFT", "RIGHT", "INFO", "LCD_BACKLIGHT", "HOTKEY1", "HOTKEY2", "HOTKEY3"}; -#define REMOTE_MAX_KEYS (sizeof(rc_keydesc)/sizeof(char*)) -alt_u16 rc_keymap[REMOTE_MAX_KEYS] = {0x3E29, 0x3EA9, 0x3E69, 0x3E4D, 0x3EED, 0x3E2D, 0x3ECD, 0x3EAD, 0x3E6D, 0x3E65, 0x3E01, 0x3EC1, 0x3E41, 0x3EA1}; - -typedef enum { - RC_BTN1 = 0, - RC_BTN2, - RC_BTN3, - RC_MENU, - RC_BACK, - RC_UP, - RC_DOWN, - RC_LEFT, - RC_RIGHT, - RC_INFO, - RC_LCDBL, - RC_HOTKEY1, - RC_HOTKEY2, - RC_HOTKEY3, -} rc_code_t; - -#define lcd_write_menu() lcd_write((char*)&menu_row1, (char*)&menu_row2) -#define lcd_write_status() lcd_write((char*)&row1, (char*)&row2) - -static const char *avinput_str[] = { "NO MODE", "AV1: RGBS", "AV1: RGsB", "AV2: YPbPr", "AV2: RGsB", "AV3: RGBHV", "AV3: RGBS", "AV3: RGsB" }; -static const char *l3_mode_desc[] = { "Generic 16:9", "Generic 4:3", "320x240 optim.", "256x240 optim." }; -static const char *s480p_desc[] = { "Auto", "DTV 480p", "VGA 640x480" }; -static const char *sl_mode_desc[] = { "Off", "Horizontal", "Vertical" }; -static const char *sync_lpf_desc[] = { "Off", "33MHz", "10MHz", "2.5MHz" }; -static const char *video_lpf_desc[] = { "Auto", "Off", "95MHz (HDTV II)", "35MHz (HDTV I)", "16MHz (EDTV)", "9MHz (SDTV)" }; - -typedef enum { - AV_KEEP = 0, - AV1_RGBs = 1, - AV1_RGsB = 2, - AV2_YPBPR = 3, - AV2_RGsB = 4, - AV3_RGBHV = 5, - AV3_RGBs = 6, - AV3_RGsB = 7 -} avinput_t; - -// In reverse order of importance -typedef enum { - NO_CHANGE = 0, - INFO_CHANGE = 1, - MODE_CHANGE = 2, - TX_MODE_CHANGE = 3, - ACTIVITY_CHANGE = 4 -} status_t; - -typedef enum { - SCANLINE_MODE, - SCANLINE_STRENGTH, - SCANLINE_ID, - H_MASK, - V_MASK, - SAMPLER_480P, - SAMPLER_PHASE, - YPBPR_COLORSPACE, - SYNC_THOLD, - PRE_COAST, - POST_COAST, - SYNC_LPF, - VIDEO_LPF, - DISABLE_ALC, - LINETRIPLE_ENABLE, - LINETRIPLE_MODE, - TX_MODE, -#ifndef DEBUG - FW_UPDATE, -#endif - SAVE_CONFIG -} menuitem_id; - -typedef enum { - NO_ACTION = 0, - NEXT_PAGE = 1, - PREV_PAGE = 2, - VAL_PLUS = 3, - VAL_MINUS = 4, -} menucode_id; - -typedef enum { - TX_HDMI = 0, - TX_DVI = 1 -} tx_mode_t; - -typedef struct { - alt_u8 sl_mode; - alt_u8 sl_str; - alt_u8 sl_id; - alt_u8 linemult_target; - alt_u8 l3_mode; - alt_u8 h_mask; - alt_u8 v_mask; - alt_u8 tx_mode; - alt_u8 s480p_mode; - alt_8 sampler_phase; - alt_u8 ypbpr_cs; - alt_8 sync_thold; - alt_u8 sync_lpf; - alt_u8 video_lpf; - alt_u8 pre_coast; - alt_u8 post_coast; - alt_u8 disable_alc; -} avconfig_t; - -// Target configuration -avconfig_t tc; - -//TODO: transform binary values into flags -typedef struct { - alt_u32 totlines; - alt_u32 clkcnt; - alt_u8 progressive; - alt_u8 macrovis; - alt_u8 refclk; - alt_8 id; - alt_u8 sync_active; - alt_u8 linemult; - avinput_t avinput; - // Current configuration - avconfig_t cc; -} avmode_t; - -// Current mode -avmode_t cm; - -typedef struct { - const menuitem_id id; - const char *desc; -} menuitem_t; - -const menuitem_t menu[] = { - { SCANLINE_MODE, "Scanlines" }, - { SCANLINE_STRENGTH, "Scanline str." }, - { SCANLINE_ID, "Scanline id" }, - { H_MASK, "Horizontal mask" }, - { V_MASK, "Vertical mask" }, - { SAMPLER_480P, "480p in sampler" }, - { SAMPLER_PHASE, "Sampling phase" }, - { YPBPR_COLORSPACE, "YPbPr in ColSpa" }, - { SYNC_THOLD, "Analog sync thld" }, - { PRE_COAST, "H-PLL Pre-Coast" }, - { POST_COAST, "H-PLL Post-Coast" }, - { SYNC_LPF, "Analog sync LPF" }, - { VIDEO_LPF, "Video LPF" }, - { DISABLE_ALC, "Auto Lev. Contr." }, - { LINETRIPLE_ENABLE, "240p/288p lineX3" }, - { LINETRIPLE_MODE, "Linetriple mode" }, - { TX_MODE, "TX mode" }, -#ifndef DEBUG - { FW_UPDATE, "Firmware update" }, -#endif - { SAVE_CONFIG, "Save settings" }, -}; - -#define MENUITEMS (sizeof(menu)/sizeof(menuitem_t)) - -typedef struct { - char fw_key[4]; - alt_u8 version_major; - alt_u8 version_minor; - char version_suffix[8]; - alt_u32 hdr_len; - alt_u32 data_len; - alt_u32 data_crc; - alt_u32 hdr_crc; -} fw_hdr; - -#define USERDATA_HDR_SIZE 11 -typedef struct { - char userdata_key[8]; - alt_u8 version_major; - alt_u8 version_minor; - alt_u8 num_entries; -} userdata_hdr; - -#define USERDATA_ENTRY_HDR_SIZE 2 -typedef struct { - alt_u8 type; - alt_u8 entry_len; -} userdata_entry; - -typedef enum { - UDE_REMOTE_MAP = 0, - UDE_AVCONFIG, -} userdata_entry_type; - -extern mode_data_t video_modes[]; -extern ypbpr_to_rgb_csc_t csc_coeffs[]; -extern alt_epcq_controller_dev epcq_controller_0; - -alt_epcq_controller_dev *epcq_controller_dev; -alt_up_sd_card_dev *sdcard_dev; - -alt_u8 target_typemask; -alt_u8 target_type; -alt_u8 stable_frames; - -char row1[LCD_ROW_LEN+1], row2[LCD_ROW_LEN+1], menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; - -// EPCS16 pagesize is 256 bytes -// Flash is split 50-50 to FW and userdata, 1MB each -#define PAGESIZE 256 -#define PAGES_PER_SECTOR 256 -#define USERDATA_OFFSET 0x100000 -#define USERDATA_MAX_SIZE 0x1000 //4KB should be enough - -// SD controller uses 512-byte chunks -#define SD_BUFFER_SIZE 512 - -short int sd_fw_handle; - -alt_u8 menu_active, menu_page; -alt_u32 remote_code; -alt_u8 remote_rpt, remote_rpt_prev; -alt_u32 btn_code, btn_code_prev; - -int check_flash() -{ - epcq_controller_dev = &epcq_controller_0; - - if ((epcq_controller_dev == NULL) || !(epcq_controller_dev->is_epcs && (epcq_controller_dev->page_size == PAGESIZE))) - return -1; - - //printf("Flash size in bytes: %d\nSector size: %d (%d pages)\nPage size: %d\n", epcq_controller_dev->size_in_bytes, epcq_controller_dev->sector_size, epcq_controller_dev->sector_size/epcq_controller_dev->page_size, epcq_controller_dev->page_size); - - return 0; -} - -int read_flash(alt_u32 offset, alt_u32 length, alt_u8 *dstbuf) -{ - int retval, i; - - retval = alt_epcq_controller_read(&epcq_controller_dev->dev, offset, dstbuf, length); - if (retval != 0) - return -1; - - for (i=0; i> 24; - - return 0; -} - -int write_flash_page(alt_u8 *pagedata, alt_u32 length, alt_u32 pagenum) -{ - int retval, i; - - if ((pagenum % PAGES_PER_SECTOR) == 0) { - printf("Erasing sector %u\n", (unsigned)(pagenum/PAGES_PER_SECTOR)); - retval = alt_epcq_controller_erase_block(&epcq_controller_dev->dev, pagenum*PAGESIZE); - - if (retval != 0) { - strncpy(menu_row1, "Flash erase", LCD_ROW_LEN+1); - sniprintf(menu_row1, LCD_ROW_LEN+1, "error %d", retval); - menu_row2[0] = '\0'; - printf("Flash erase error, sector %u\nRetval %d\n", (unsigned)(pagenum/PAGES_PER_SECTOR), retval); - return -200; - } - } - - // Bit-reverse bytes for flash - for (i=0; i> 24; - - retval = alt_epcq_controller_write_block(&epcq_controller_dev->dev, (pagenum/PAGES_PER_SECTOR)*PAGES_PER_SECTOR*PAGESIZE, pagenum*PAGESIZE, pagedata, length); - - if (retval != 0) { - strncpy(menu_row1, "Flash write", LCD_ROW_LEN+1); - strncpy(menu_row2, "error", LCD_ROW_LEN+1); - printf("Flash write error, page %u\nRetval %d\n", (unsigned)pagenum, retval); - return -201; - } - - return retval; -} - -int verify_flash(alt_u32 offset, alt_u32 length, alt_u32 golden_crc, alt_u8 *tmpbuf) -{ - alt_u32 crcval=0, i, bytes_to_read; - int retval; - - for (i=0; i 512)) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "Invalid read cmd"); - menu_row2[0] = '\0'; - return -1; - } - - if (!Read_Sector_Data((offset/SD_BUFFER_SIZE), 0)) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "SD read failure"); - menu_row2[0] = '\0'; - return -2; - } - - // Copy buffer to SW - for (i=0; ibase, i); - *((alt_u32*)(dstbuf+i)) = tmp; - } - - return 0; -} - -int check_sdcard(alt_u8 *databuf) -{ - sdcard_dev = alt_up_sd_card_open_dev(ALTERA_UP_SD_CARD_AVALON_INTERFACE_0_NAME); - - if ((sdcard_dev == NULL) || !alt_up_sd_card_is_Present()) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "No SD card det."); - menu_row2[0] = '\0'; - return 1; - } - - return read_sd_block(0, 512, databuf); -} - -int check_fw_header(alt_u8 *databuf, fw_hdr *hdr) -{ - alt_u32 crcval, tmp; - - strncpy(hdr->fw_key, (char*)databuf, 4); - if (strncmp(hdr->fw_key, "OSSC", 4)) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "Invalid image"); - menu_row2[0] = '\0'; - return 1; - } - - hdr->version_major = databuf[4]; - hdr->version_minor = databuf[5]; - strncpy(hdr->version_suffix, (char*)(databuf+6), 8); - hdr->version_suffix[7] = 0; - - memcpy(&tmp, databuf+14, 4); - hdr->hdr_len = ALT_CI_NIOS_CUSTOM_INSTR_ENDIANCONVERTER_0(tmp); - memcpy(&tmp, databuf+18, 4); - hdr->data_len = ALT_CI_NIOS_CUSTOM_INSTR_ENDIANCONVERTER_0(tmp); - memcpy(&tmp, databuf+22, 4); - hdr->data_crc = ALT_CI_NIOS_CUSTOM_INSTR_ENDIANCONVERTER_0(tmp); - // Always at bytes [508-511] - memcpy(&tmp, databuf+508, 4); - hdr->hdr_crc = ALT_CI_NIOS_CUSTOM_INSTR_ENDIANCONVERTER_0(tmp); - - if (hdr->hdr_len < 26 || hdr->hdr_len > 508) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "Invalid header"); - menu_row2[0] = '\0'; - return -1; - } - - crcval = crcCI(databuf, hdr->hdr_len, 1); - - if (crcval != hdr->hdr_crc) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "Invalid hdr CRC"); - menu_row2[0] = '\0'; - return -2; - } - - return 0; -} - -int check_fw_image(alt_u32 offset, alt_u32 size, alt_u32 golden_crc, alt_u8 *tmpbuf) -{ - alt_u32 crcval=0, i, bytes_to_read; - int retval; - - for (i=0; i PAGESIZE) { - retval = write_flash_page(databuf+PAGESIZE, (bytes_to_rw-PAGESIZE), (i/PAGESIZE)+1); - if (retval != 0) - goto failure; - } - } - - strncpy(menu_row1, "Verifying flash", LCD_ROW_LEN+1); - strncpy(menu_row2, "please wait...", LCD_ROW_LEN+1); - lcd_write_menu(); - retval = verify_flash(0, fw_header.data_len, fw_header.data_crc, databuf); - if (retval != 0) - goto failure; - - return 0; - - -failure: - lcd_write_menu(); - usleep(1000000); - - // Probable rw error, retry update - if ((retval <= -200) && (retries > 0)) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "Retrying update"); - retries--; - goto update_init; - } - - return -1; -} - -int write_userdata() -{ - alt_u8 databuf[PAGESIZE]; - int retval; - - strncpy((char*)databuf, "USRDATA", 8); - databuf[8] = fw_ver_major; - databuf[9] = fw_ver_minor; - databuf[10] = 2; - - retval = write_flash_page(databuf, USERDATA_HDR_SIZE, (USERDATA_OFFSET/PAGESIZE)); - if (retval != 0) { - return -1; - } - - databuf[0] = UDE_REMOTE_MAP; - databuf[1] = 4+sizeof(rc_keymap); - databuf[2] = databuf[3] = 0; //padding - memcpy(databuf+4, rc_keymap, sizeof(rc_keymap)); - - retval = write_flash_page(databuf, databuf[1], (USERDATA_OFFSET/PAGESIZE)+1); - if (retval != 0) { - return -1; - } - - databuf[0] = UDE_AVCONFIG; - databuf[1] = 4+sizeof(avconfig_t); - databuf[2] = databuf[3] = 0; //padding - memcpy(databuf+4, &tc, sizeof(avconfig_t)); - - retval = write_flash_page(databuf, databuf[1], (USERDATA_OFFSET/PAGESIZE)+2); - if (retval != 0) { - return -1; - } - - return 0; -} - - -void set_default_avconfig() -{ - memset(&cm.cc, 0, sizeof(avconfig_t)); - memset(&tc, 0, sizeof(avconfig_t)); - cm.cc.pre_coast = DEFAULT_PRE_COAST; - tc.pre_coast = DEFAULT_PRE_COAST; - cm.cc.post_coast = DEFAULT_POST_COAST; - tc.post_coast = DEFAULT_POST_COAST; -} - -int read_userdata() -{ - int retval, i; - alt_u8 databuf[PAGESIZE]; - userdata_hdr udhdr; - userdata_entry udentry; - - retval = read_flash(USERDATA_OFFSET, USERDATA_HDR_SIZE, databuf); - if (retval != 0) { - printf("Flash read error\n"); - return -1; - } - - strncpy(udhdr.userdata_key, (char*)databuf, 8); - if (strncmp(udhdr.userdata_key, "USRDATA", 8)) { - printf("No userdata found on flash\n"); - return 1; - } - - udhdr.version_major = databuf[8]; - udhdr.version_minor = databuf[9]; - udhdr.num_entries = databuf[10]; - - //TODO: check version compatibility - printf("Userdata: v%u.%.2u, %u entries\n", udhdr.version_major, udhdr.version_minor, udhdr.num_entries); - - for (i=0; i 0)) - tc.h_mask--; - else if ((code == VAL_PLUS) && (tc.h_mask < HV_MASK_MAX)) - tc.h_mask++; - sniprintf(menu_row2, LCD_ROW_LEN+1, "%u pixels", tc.h_mask); - break; - case V_MASK: - if ((code == VAL_MINUS) && (tc.v_mask > 0)) - tc.v_mask--; - else if ((code == VAL_PLUS) && (tc.v_mask < HV_MASK_MAX)) - tc.v_mask++; - sniprintf(menu_row2, LCD_ROW_LEN+1, "%u pixels", tc.v_mask); - break; - case SAMPLER_480P: - if (code == VAL_MINUS) - tc.s480p_mode = tc.s480p_mode ? tc.s480p_mode-1 : S480P_MODE_MAX; - else if (code == VAL_PLUS) - tc.s480p_mode = tc.s480p_mode < S480P_MODE_MAX ? tc.s480p_mode+1 : 0; - strncpy(menu_row2, s480p_desc[tc.s480p_mode], LCD_ROW_LEN+1); - break; - case SAMPLER_PHASE: - if (code == VAL_MINUS) - tc.sampler_phase = tc.sampler_phase > SAMPLER_PHASE_MIN ? tc.sampler_phase-1 : SAMPLER_PHASE_MAX; - else if (code == VAL_PLUS) - tc.sampler_phase = tc.sampler_phase < SAMPLER_PHASE_MAX ? tc.sampler_phase+1 : SAMPLER_PHASE_MIN; - sniprintf(menu_row2, LCD_ROW_LEN+1, "%d deg", ((tc.sampler_phase-SAMPLER_PHASE_MIN)*1125)/100); - break; - case YPBPR_COLORSPACE: - if ((code == VAL_MINUS) || (code == VAL_PLUS)) - tc.ypbpr_cs = !tc.ypbpr_cs; - strncpy(menu_row2, csc_coeffs[tc.ypbpr_cs].name, LCD_ROW_LEN+1); - break; - case SYNC_THOLD: - if (code == VAL_MINUS) - tc.sync_thold = tc.sync_thold > SYNC_THOLD_MIN ? tc.sync_thold-1 : SYNC_THOLD_MAX; - else if (code == VAL_PLUS) - tc.sync_thold = tc.sync_thold < SYNC_THOLD_MAX ? tc.sync_thold+1 : SYNC_THOLD_MIN; - sniprintf(menu_row2, LCD_ROW_LEN+1, "%d mV", ((tc.sync_thold-SYNC_THOLD_MIN)*1127)/100); - break; - case PRE_COAST: - if ((code == VAL_MINUS) && (tc.pre_coast > PLL_COAST_MIN)) - tc.pre_coast--; - else if ((code == VAL_PLUS) && (tc.pre_coast < PLL_COAST_MAX)) - tc.pre_coast++; - sniprintf(menu_row2, LCD_ROW_LEN+1, "%u lines", tc.pre_coast); - break; - case POST_COAST: - if ((code == VAL_MINUS) && (tc.post_coast > PLL_COAST_MIN)) - tc.post_coast--; - else if ((code == VAL_PLUS) && (tc.post_coast < PLL_COAST_MAX)) - tc.post_coast++; - sniprintf(menu_row2, LCD_ROW_LEN+1, "%u lines", tc.post_coast); - break; - case SYNC_LPF: - if (code == VAL_MINUS) - tc.sync_lpf = tc.sync_lpf ? tc.sync_lpf-1 : SYNC_LPF_MAX; - else if (code == VAL_PLUS) - tc.sync_lpf = tc.sync_lpf < SYNC_LPF_MAX ? tc.sync_lpf+1 : 0; - strncpy(menu_row2, sync_lpf_desc[tc.sync_lpf], LCD_ROW_LEN+1); - break; - case VIDEO_LPF: - if (code == VAL_MINUS) - tc.video_lpf = tc.video_lpf ? tc.video_lpf-1 : VIDEO_LPF_MAX; - else if (code == VAL_PLUS) - tc.video_lpf = tc.video_lpf < VIDEO_LPF_MAX ? tc.video_lpf+1 : 0; - strncpy(menu_row2, video_lpf_desc[tc.video_lpf], LCD_ROW_LEN+1); - break; - case LINETRIPLE_ENABLE: - if ((code == VAL_MINUS) || (code == VAL_PLUS)) - tc.linemult_target = !tc.linemult_target; - sniprintf(menu_row2, LCD_ROW_LEN+1, tc.linemult_target ? "On" : "Off"); - break; - case LINETRIPLE_MODE: - if (code == VAL_MINUS) - tc.l3_mode = tc.l3_mode ? tc.l3_mode-1 : L3_MODE_MAX; - else if (code == VAL_PLUS) - tc.l3_mode = tc.l3_mode < L3_MODE_MAX ? tc.l3_mode+1 : 0; - strncpy(menu_row2, l3_mode_desc[tc.l3_mode], LCD_ROW_LEN+1); - break; - case DISABLE_ALC: - if ((code == VAL_MINUS) || (code == VAL_PLUS)) - tc.disable_alc = !tc.disable_alc; - sniprintf(menu_row2, LCD_ROW_LEN+1, tc.disable_alc ? "Disabled" : "Enabled"); - break; - case TX_MODE: - if (!(IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & HDMITX_MODE_MASK) && ((code == VAL_MINUS) || (code == VAL_PLUS))) { - tc.tx_mode = !tc.tx_mode; - TX_enable(tc.tx_mode); - } - sniprintf(menu_row2, LCD_ROW_LEN+1, tc.tx_mode ? "DVI" : "HDMI"); - break; -#ifndef DEBUG - case FW_UPDATE: - if ((code == VAL_MINUS) || (code == VAL_PLUS)) { - retval = fw_update(); - if (retval == 0) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "Fw update OK"); - sniprintf(menu_row2, LCD_ROW_LEN+1, "Please restart"); - } else { - sniprintf(menu_row1, LCD_ROW_LEN+1, "FW not"); - sniprintf(menu_row2, LCD_ROW_LEN+1, "updated"); - } - } else { - sniprintf(menu_row2, LCD_ROW_LEN+1, "press <- or ->"); - } - break; -#endif - case SAVE_CONFIG: - if ((code == VAL_MINUS) || (code == VAL_PLUS)) { - retval = write_userdata(); - if (retval == 0) { - sniprintf(menu_row2, LCD_ROW_LEN+1, "Done"); - } else { - sniprintf(menu_row2, LCD_ROW_LEN+1, "error"); - } - } else { - sniprintf(menu_row2, LCD_ROW_LEN+1, "press <- or ->"); - } - break; - default: - sniprintf(menu_row2, LCD_ROW_LEN+1, "MISSING ITEM"); - break; - } - - lcd_write_menu(); - - return; -} - -void read_control() -{ - if (remote_code == rc_keymap[RC_MENU]) { - menu_active = !menu_active; - - if (menu_active) - display_menu(1); - else - lcd_write_status(); - } else if (remote_code == rc_keymap[RC_INFO]) { - sniprintf(menu_row1, LCD_ROW_LEN+1, "VMod: %s", video_modes[cm.id].name); - //sniprintf(menu_row1, LCD_ROW_LEN+1, "0x%x 0x%x 0x%x", ths_readreg(THS_CH1), ths_readreg(THS_CH2), ths_readreg(THS_CH3)); - sniprintf(menu_row2, LCD_ROW_LEN+1, "LO: %u VSM: %u", IORD_ALTERA_AVALON_PIO_DATA(PIO_4_BASE) & 0xffff, (IORD_ALTERA_AVALON_PIO_DATA(PIO_4_BASE) >> 16) & 0x3); - lcd_write_menu(); - printf("Mod: %s\n", video_modes[cm.id].name); - printf("Lines: %u M: %u\n", IORD_ALTERA_AVALON_PIO_DATA(PIO_4_BASE) & 0xffff, cm.macrovis); - } else if (remote_code == rc_keymap[RC_LCDBL]) { - IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, (IORD_ALTERA_AVALON_PIO_DATA(PIO_0_BASE) ^ (1<<1))); - } else if (remote_code == rc_keymap[RC_HOTKEY1]) { - //tc.sl_mode = (tc.sl_mode > 0) ? 0 : 1; - tc.sl_mode = tc.sl_mode < SL_MODE_MAX ? tc.sl_mode+1 : 0; - } else if (remote_code == rc_keymap[RC_HOTKEY2]) { - //if (tc.sl_str > 0) - // tc.sl_str--; - tc.sl_str = tc.sl_str ? tc.sl_str-1 : SCANLINESTR_MAX; - } else if (remote_code == rc_keymap[RC_HOTKEY3]) { - //if (tc.sl_str < SCANLINESTR_MAX) - // tc.sl_str++; - tc.sl_str = tc.sl_str < SCANLINESTR_MAX ? tc.sl_str+1 : 0; - } - - if (btn_code_prev == 0) { - if (btn_code & PB1_BIT) - tc.sl_mode = (tc.sl_mode > 0) ? 0 : 1; - } - - if (menu_active) - display_menu(0); -} - -void set_lpf(alt_u8 lpf) -{ - alt_u32 pclk; - pclk = (clkrate[cm.refclk]/cm.clkcnt)*video_modes[cm.id].h_total; - printf("PCLK: %uHz\n", pclk); - - //Auto - if (lpf == 0) { - switch (target_type) { - case VIDEO_PC: - tvp_set_lpf((pclk < 30000000) ? 0x0F : 0); - ths_set_lpf(THS_LPF_BYPASS); - break; - case VIDEO_HDTV: - tvp_set_lpf(0); - ths_set_lpf(THS_LPF_BYPASS); - break; - case VIDEO_EDTV: - tvp_set_lpf(0); - ths_set_lpf(1); - break; - case VIDEO_SDTV: - case VIDEO_LDTV: - tvp_set_lpf(0); - ths_set_lpf(0); - break; - default: - break; - } - } else { - tvp_set_lpf((tc.video_lpf == 2) ? 0x0F : 0); - ths_set_lpf((tc.video_lpf > 2) ? (VIDEO_LPF_MAX-tc.video_lpf) : THS_LPF_BYPASS); - } -} - -// Check if input video status / target configuration has changed -status_t get_status(tvp_input_t input) -{ - alt_u32 data1, data2; - alt_u32 totlines, clkcnt; - alt_u8 progressive; - //alt_u8 refclk; - alt_u8 sync_active; - alt_u8 vsyncmode; - alt_u16 fpga_totlines; - status_t status; - static alt_u8 act_ctr; - alt_u32 ctr; - - status = NO_CHANGE; - - // Wait until vsync active (avoid noise coupled to I2C bus on earlier prototypes) - for (ctr=0; ctr> 16; - - // TVP7002 may randomly report "no sync" (especially with arcade boards), - // thus disable output only after N consecutive "no sync"-events - if (!cm.sync_active && sync_active) { - cm.sync_active = sync_active; - status = ACTIVITY_CHANGE; - act_ctr = 0; - } else if (cm.sync_active && !sync_active) { - printf("Sync down in %u...\n", SYNC_LOSS_THOLD-act_ctr); - if (act_ctr >= SYNC_LOSS_THOLD) { - act_ctr = 0; - cm.sync_active = sync_active; - status = ACTIVITY_CHANGE; - } else { - act_ctr++; - } - } else { - act_ctr = 0; - } - - - data1 = tvp_readreg(TVP_LINECNT1); - data2 = tvp_readreg(TVP_LINECNT2); - totlines = ((data2 & 0x0f) << 8) | data1; - progressive = !!(data2 & (1<<5)); - cm.macrovis = !!(data2 & (1<<6)); - - fpga_totlines = IORD_ALTERA_AVALON_PIO_DATA(PIO_4_BASE) & 0xffff; - - //TODO: check flags instead - if (vsyncmode == 0x2) { - progressive = 1; - } else if ((vsyncmode == 0x1) && fpga_totlines > ((totlines-1)*2)) { - progressive = 0; - totlines = fpga_totlines; //ugly hack - } - - data1 = tvp_readreg(TVP_CLKCNT1); - data2 = tvp_readreg(TVP_CLKCNT2); - clkcnt = ((data2 & 0x0f) << 8) | data1; - - if ((progressive && (totlines > MIN_LINES_PROGRESSIVE)) || (!progressive && (totlines > MIN_LINES_INTERLACED))) { - if ((abs((alt_16)totlines - (alt_16)cm.totlines) > LINECNT_THOLD) || (clkcnt != cm.clkcnt) || (progressive != cm.progressive)) { - printf("totlines: %u (cur) / %u (prev), clkcnt: %u (cur) / %u (prev). Data1: 0x%.2x, Data2: 0x%.2x\n", (unsigned)totlines, (unsigned)cm.totlines, (unsigned)clkcnt, (unsigned)cm.clkcnt, (unsigned)data1, (unsigned)data2); - stable_frames = 0; - } else if (stable_frames != STABLE_THOLD) { - stable_frames++; - if (stable_frames == STABLE_THOLD) - status = (status < MODE_CHANGE) ? MODE_CHANGE : status; - } - - - if ((tc.linemult_target != cm.cc.linemult_target) || - (tc.l3_mode != cm.cc.l3_mode) || - ((tc.s480p_mode != cm.cc.s480p_mode) && (video_modes[cm.id].flags & (MODE_DTV480P|MODE_VGA480P)))) - status = (status < MODE_CHANGE) ? MODE_CHANGE : status; - - - if (tc.disable_alc != cm.cc.disable_alc) - tvp_set_alc(tc.disable_alc, target_type); - - - cm.totlines = totlines; - cm.clkcnt = clkcnt; - cm.progressive = progressive; - } - - if ((tc.sl_mode != cm.cc.sl_mode) || - (tc.sl_str != cm.cc.sl_str) || - (tc.sl_id != cm.cc.sl_id) || - (tc.h_mask != cm.cc.h_mask) || - (tc.v_mask != cm.cc.v_mask)) - status = (status < INFO_CHANGE) ? INFO_CHANGE : status; - - if (tc.sampler_phase != cm.cc.sampler_phase) - tvp_set_hpll_phase(tc.sampler_phase-SAMPLER_PHASE_MIN); - - if (tc.sync_thold != cm.cc.sync_thold) - tvp_set_sog_thold(tc.sync_thold-SYNC_THOLD_MIN); - - if ((tc.pre_coast != cm.cc.pre_coast) || (tc.post_coast != cm.cc.post_coast)) - tvp_set_hpllcoast(tc.pre_coast, tc.post_coast); - - if (tc.ypbpr_cs != cm.cc.ypbpr_cs) - tvp_sel_csc(&csc_coeffs[tc.ypbpr_cs]); - - if (tc.video_lpf != cm.cc.video_lpf) - set_lpf(tc.video_lpf); - - if (tc.sync_lpf != cm.cc.sync_lpf) - tvp_set_sync_lpf(tc.sync_lpf); - - // use memcpy instead? - cm.cc = tc; - - return status; -} - -// h_info: [31:30] [29:28] [27:22] [21] [20:10] [7:0] -// | H_LINEMULT[1:0] | H_L3MODE[1:0] | H_MASK[5:0] | | H_ACTIVE[10:0] | H_BACKPORCH[7:0] | -// -// v_info: [31] [30] [29] [28:25] [24:19] [18] [17:7] [6] [5:0] -// | V_SCANLINES | V_SCANLINEDIR | V_SCANLINEID | V_SCANLINESTR[3:0] | V_MASK[5:0] | | V_ACTIVE[10:0] | | V_BACKPORCH[5:0] | -void set_videoinfo() -{ - alt_u8 slid_target; - - if (video_modes[cm.id].flags & MODE_L3ENABLE_MASK) { - cm.linemult = 2; - slid_target = cm.cc.sl_id ? 2 : 0; - } else if (video_modes[cm.id].flags & MODE_L2ENABLE) { - cm.linemult = 1; - slid_target = cm.cc.sl_id; - } else { - cm.linemult = 0; - slid_target = cm.cc.sl_id; - } - - IOWR_ALTERA_AVALON_PIO_DATA(PIO_2_BASE, (cm.linemult<<30) | (cm.cc.l3_mode<<28) | (cm.cc.h_mask)<<22 | (video_modes[cm.id].h_active<<10) | video_modes[cm.id].h_backporch); - IOWR_ALTERA_AVALON_PIO_DATA(PIO_3_BASE, ((!!cm.cc.sl_mode)<<31) | (cm.cc.sl_mode > 0 ? (cm.cc.sl_mode-1)<<30 : 0) | (slid_target<<19) | (cm.cc.sl_str<<25) | (cm.cc.v_mask<<19) | (video_modes[cm.id].v_active<<7) | video_modes[cm.id].v_backporch); -} - -// Configure TVP7002 and scan converter logic based on the video mode -void program_mode() -{ - alt_u32 data1, data2; - alt_u32 h_hz, v_hz_x100; - - // Mark as stable (needed after sync up to avoid unnecessary mode switch) - stable_frames = STABLE_THOLD; - - if ((cm.clkcnt != 0) && (cm.totlines != 0)) { //prevent div by 0 - h_hz = clkrate[cm.refclk]/cm.clkcnt; - v_hz_x100 = cm.progressive ? (100*clkrate[cm.refclk]/cm.clkcnt)/cm.totlines : (2*(100*clkrate[cm.refclk]/cm.clkcnt))/cm.totlines; - } else { - h_hz = 15700; - v_hz_x100 = 6000; - } - - 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)); - - data1 = tvp_readreg(TVP_HSINWIDTH); - data2 = tvp_readreg(TVP_VSINWIDTH); - printf("Hswidth: %u Vswidth: %u Macrovision: %u\n", (unsigned)data1, (unsigned)(data2 & 0x1F), (unsigned)cm.macrovis); - - //TODO: rewrite with strncpy to reduce code size - 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)); - //strncpy(row1, avinput_str[cm.avinput], LCD_ROW_LEN+1); - //strncpy(row2, avinput_str[cm.avinput], LCD_ROW_LEN+1); - if (!menu_active) - lcd_write_status(); - - //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, target_typemask, cm.cc.linemult_target, cm.cc.l3_mode, cm.cc.s480p_mode); - - if ( cm.id == -1) { - printf ("Error: no suitable mode found, defaulting to 240p\n"); - cm.id = 4; - } - - target_type = target_typemask & video_modes[cm.id].type; - - printf("Mode %s selected\n", video_modes[cm.id].name); - - tvp_source_setup(cm.id, target_type, cm.cc.disable_alc, (cm.progressive ? cm.totlines : cm.totlines/2), v_hz_x100/100, cm.refclk, cm.cc.pre_coast, cm.cc.post_coast); - set_lpf(cm.cc.video_lpf); - set_videoinfo(); -} - -// Initialize hardware -int init_hw() -{ - alt_u32 chiprev; - - // Reset error vector and scan converter - IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, 0x03); - IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, 0x00); - IOWR_ALTERA_AVALON_PIO_DATA(PIO_2_BASE, 0x00000000); - IOWR_ALTERA_AVALON_PIO_DATA(PIO_3_BASE, 0x00000000); - usleep(10000); - - // unreset hw - IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, 0x03); - - //wait >500ms for SD card interface to be stable - //over 200ms and LCD may be buggy? - usleep(200000); - - // IT6613 officially supports only 100kHz, but 400kHz seems to work - I2C_init(I2CA_BASE,ALT_CPU_FREQ,400000); - - /* Initialize the character display */ - lcd_init(); - - if (!ths_init()) { - printf("Error: could not read from THS7353\n"); - return -2; - } - - /* check if TVP is found */ - chiprev = tvp_readreg(TVP_CHIPREV); - //printf("chiprev %d\n", chiprev); - - if ( chiprev == 0xff) { - printf("Error: could not read from TVP7002\n"); - return -3; - } - - tvp_init(); - - chiprev = HDMITX_ReadI2C_Byte(IT_DEVICEID); - - if ( chiprev != 0x13) { - printf("Error: could not read from IT6613\n"); - return -4; - } - - InitIT6613(); - - if (check_flash() != 0) { - printf("Error: incorrect flash type detected\n"); - return -1; - } - - set_default_avconfig(); - - // safe? - read_userdata(); - - // enforce DVI mode on non-DIY boards - if ((IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & HDMITX_MODE_MASK)) { - cm.cc.tx_mode = TX_DVI; - tc.tx_mode = TX_DVI; - } - - if (!(IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & PB1_BIT)) - setup_rc(); - - // init always is HDMI mode (fixes yellow screen bug) - TX_enable(TX_HDMI); - if (cm.cc.tx_mode) - TX_enable(cm.cc.tx_mode); - - return 0; -} - -// Enable chip outputs -void enable_outputs() -{ - // program video mode - program_mode(); - // enable TVP output - tvp_enable_output(); - - // enable and unmute HDMITX - // TODO: check pclk - TX_enable(cm.cc.tx_mode); -} - -int main() -{ - tvp_input_t target_input = 0; - ths_input_t target_ths = 0; - video_format target_format = 0; - avinput_t target_mode; - - alt_u8 av_init = 0; - status_t status; - - alt_u32 input_vec; - - int init_stat; - - init_stat = init_hw(); - - if (init_stat >= 0) { - printf("### DIY VIDEO DIGITIZER / SCANCONVERTER INIT OK ###\n\n"); - sniprintf(row1, LCD_ROW_LEN+1, "OSSC fw. %u.%.2u", fw_ver_major, fw_ver_minor); -#ifndef DEBUG - strncpy(row2, "2014-2016 marqs", LCD_ROW_LEN+1); -#else - strncpy(row2, "** DEBUG BUILD *", LCD_ROW_LEN+1); -#endif - lcd_write_status(); - } else { - sniprintf(row1, LCD_ROW_LEN+1, "Init error %d", init_stat); - strncpy(row2, "", LCD_ROW_LEN+1); - lcd_write_status(); - while (1) {} - } - - while(1) { - // Select target input and mode - input_vec = IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE); - remote_code = input_vec & RC_MASK; - btn_code = ~input_vec & PB_MASK; - remote_rpt = input_vec >> 24; - - if ((remote_rpt == 0) || ((remote_rpt > 1) && (remote_rpt < 6)) || (remote_rpt == remote_rpt_prev)) - remote_code = 0; - /*else if ((remote_rpt >= 6) && (remote_rpt % 2)) - remote_code = 0;*/ - - if (remote_code) - printf("RCODE: 0x%.4x, %u\n", remote_code, remote_rpt); - - if (btn_code_prev == 0 && btn_code != 0) - printf("BCODE: 0x%.2x\n", btn_code>>16); - - target_mode = AV_KEEP; - - if (remote_code == rc_keymap[RC_BTN1]) { - if (cm.avinput == AV1_RGBs) - target_mode = AV1_RGsB; - else - target_mode = AV1_RGBs; - } else if (remote_code == rc_keymap[RC_BTN2]) { - if (cm.avinput == AV2_YPBPR) - target_mode = AV2_RGsB; - else - target_mode = AV2_YPBPR; - } else if (remote_code == rc_keymap[RC_BTN3]) { - if (cm.avinput == AV3_RGBHV) - target_mode = AV3_RGBs; - else if (cm.avinput == AV3_RGBs) - target_mode = AV3_RGsB; - else - target_mode = AV3_RGBHV; - } - - if ((btn_code_prev == 0) && (btn_code & PB0_BIT)) { - target_mode = (cm.avinput == AV3_RGsB) ? AV1_RGBs : (cm.avinput+1); - } - - if (target_mode == cm.avinput) - target_mode = AV_KEEP; - - if (target_mode != AV_KEEP) - printf("### SWITCH MODE TO %s ###\n", avinput_str[target_mode]); - - switch (target_mode) { - case AV1_RGBs: - target_input = TVP_INPUT1; - target_format = FORMAT_RGBS; - target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; - target_ths = THS_INPUT_B; - break; - case AV1_RGsB: - target_input = TVP_INPUT1; - target_format = FORMAT_RGsB; - target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; - target_ths = THS_INPUT_B; - break; - case AV2_YPBPR: - target_input = TVP_INPUT1; - target_format = FORMAT_YPbPr; - target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; - target_ths = THS_INPUT_A; - break; - case AV2_RGsB: - target_input = TVP_INPUT1; - target_format = FORMAT_RGsB; - target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; - target_ths = THS_INPUT_A; - break; - case AV3_RGBHV: - target_input = TVP_INPUT3; - target_format = FORMAT_RGBHV; - target_typemask = VIDEO_PC; - target_ths = THS_STANDBY; - break; - case AV3_RGBs: - target_input = TVP_INPUT3; - target_format = FORMAT_RGBS; - target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; - target_ths = THS_STANDBY; - break; - case AV3_RGsB: - target_input = TVP_INPUT3; - target_format = FORMAT_RGsB; - target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; - target_ths = THS_STANDBY; - break; - default: - break; - } - - if (target_mode != AV_KEEP) { - av_init = 1; - cm.avinput = target_mode; - 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_source_sel(target_input, target_format, cm.refclk); - cm.clkcnt = 0; //TODO: proper invalidate - strncpy(row1, avinput_str[cm.avinput], LCD_ROW_LEN+1); - strncpy(row2, " NO SYNC", LCD_ROW_LEN+1); - if (!menu_active) - lcd_write_status(); - } - - //usleep(MAINLOOP_SLEEP_US); - usleep(300); //avoid triggering multiple times per vsync - read_control(); - - if (av_init) { - status = get_status(target_input); - - switch (status) { - case ACTIVITY_CHANGE: - if (cm.sync_active) { - printf("Sync up\n"); - IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, (IORD_ALTERA_AVALON_PIO_DATA(PIO_0_BASE) | (1<<2))); //disable videogen - enable_outputs(); - } else { - printf("Sync lost\n"); - cm.clkcnt = 0; //TODO: proper invalidate - tvp_disable_output(); - //ths_source_sel(THS_STANDBY, 0); - strncpy(row1, avinput_str[cm.avinput], LCD_ROW_LEN+1); - strncpy(row2, " NO SYNC", LCD_ROW_LEN+1); - if (!menu_active) - lcd_write_status(); - } - break; - case MODE_CHANGE: - if (cm.sync_active) { - printf("Mode change\n"); - program_mode(); - } - break; - case INFO_CHANGE: - if (cm.sync_active) { - printf("Info change\n"); - set_videoinfo(); - } - break; - default: - break; - } - } - - btn_code_prev = btn_code; - remote_rpt_prev = remote_rpt; - } - - return 0; -} diff --git a/software/sys_controller/main.c b/software/sys_controller/main.c new file mode 100644 index 0000000..5febdaf --- /dev/null +++ b/software/sys_controller/main.c @@ -0,0 +1,251 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#include +#include +#include "system.h" +#include "string.h" +#include "altera_avalon_pio_regs.h" +#include "Altera_UP_SD_Card_Avalon_Interface_mod.h" +#include "altera_epcq_controller_mod.h" +#include "i2c_opencores.h" +#include "tvp7002.h" +#include "ths7353.h" +#include "lcd.h" +#include "sysconfig.h" +#include "hdmitx.h" +#include "ci_crc.h" +#include "cfg.h" +#include "av_controller.h" +#include "controls.h" +#include "memory.h" +#include "menu.h" +#include "fw_version.h" + + +extern const char const *avinput_str[]; + +extern char row1[LCD_ROW_LEN+1], row2[LCD_ROW_LEN+1], menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; + +extern alt_u16 rc_keymap[REMOTE_MAX_KEYS]; + +extern volatile alt_u32 remote_code; +extern volatile alt_u8 remote_rpt, remote_rpt_prev; +extern volatile alt_u32 btn_code, btn_code_prev; + +extern volatile alt_u8 menu_active; + +extern alt_u8 target_typemask; + +// Target configuration +extern volatile avconfig_t tc; + +// Current mode +extern volatile avmode_t cm; + +int main() +{ + tvp_input_t target_input = 0; + ths_input_t target_ths = 0; + video_format target_format = 0; + avinput_t target_mode; + + alt_u8 av_init = 0; + status_t status; + + alt_u32 input_vec; + + int init_stat; + + init_stat = init_hw(); + + if (init_stat >= 0) { + printf("### DIY VIDEO DIGITIZER / SCANCONVERTER INIT OK ###\n\n"); + sniprintf(row1, LCD_ROW_LEN+1, "OSSC fw. %u.%.2u", FW_VER_MAJOR, FW_VER_MINOR); +#ifndef DEBUG + strncpy(row2, "2014-2016 marqs", LCD_ROW_LEN+1); +#else + strncpy(row2, "** DEBUG BUILD *", LCD_ROW_LEN+1); +#endif + lcd_write_status(); + } else { + sniprintf(row1, LCD_ROW_LEN+1, "Init error %d", init_stat); + strncpy(row2, "", LCD_ROW_LEN+1); + lcd_write_status(); + while (1) {} + } + + while(1) { + // Select target input and mode + input_vec = IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE); + remote_code = input_vec & RC_MASK; + btn_code = ~input_vec & PB_MASK; + remote_rpt = input_vec >> 24; + + if ((remote_rpt == 0) || ((remote_rpt > 1) && (remote_rpt < 6)) || (remote_rpt == remote_rpt_prev)) + remote_code = 0; + /*else if ((remote_rpt >= 6) && (remote_rpt % 2)) + remote_code = 0;*/ + + if (remote_code) + printf("RCODE: 0x%.4x, %u\n", remote_code, remote_rpt); + + if (btn_code_prev == 0 && btn_code != 0) + printf("BCODE: 0x%.2x\n", btn_code>>16); + + target_mode = AV_KEEP; + + if (remote_code == rc_keymap[RC_BTN1]) { + if (cm.avinput == AV1_RGBs) + target_mode = AV1_RGsB; + else + target_mode = AV1_RGBs; + } else if (remote_code == rc_keymap[RC_BTN2]) { + if (cm.avinput == AV2_YPBPR) + target_mode = AV2_RGsB; + else + target_mode = AV2_YPBPR; + } else if (remote_code == rc_keymap[RC_BTN3]) { + if (cm.avinput == AV3_RGBHV) + target_mode = AV3_RGBs; + else if (cm.avinput == AV3_RGBs) + target_mode = AV3_RGsB; + else + target_mode = AV3_RGBHV; + } + + if ((btn_code_prev == 0) && (btn_code & PB0_BIT)) { + target_mode = (cm.avinput == AV3_RGsB) ? AV1_RGBs : (cm.avinput+1); + } + + if (target_mode == cm.avinput) + target_mode = AV_KEEP; + + if (target_mode != AV_KEEP) + printf("### SWITCH MODE TO %s ###\n", avinput_str[target_mode]); + + switch (target_mode) { + case AV1_RGBs: + target_input = TVP_INPUT1; + target_format = FORMAT_RGBS; + target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; + target_ths = THS_INPUT_B; + break; + case AV1_RGsB: + target_input = TVP_INPUT1; + target_format = FORMAT_RGsB; + target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; + target_ths = THS_INPUT_B; + break; + case AV2_YPBPR: + target_input = TVP_INPUT1; + target_format = FORMAT_YPbPr; + target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; + target_ths = THS_INPUT_A; + break; + case AV2_RGsB: + target_input = TVP_INPUT1; + target_format = FORMAT_RGsB; + target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; + target_ths = THS_INPUT_A; + break; + case AV3_RGBHV: + target_input = TVP_INPUT3; + target_format = FORMAT_RGBHV; + target_typemask = VIDEO_PC; + target_ths = THS_STANDBY; + break; + case AV3_RGBs: + target_input = TVP_INPUT3; + target_format = FORMAT_RGBS; + target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; + target_ths = THS_STANDBY; + break; + case AV3_RGsB: + target_input = TVP_INPUT3; + target_format = FORMAT_RGsB; + target_typemask = VIDEO_LDTV|VIDEO_SDTV|VIDEO_EDTV|VIDEO_HDTV; + target_ths = THS_STANDBY; + break; + default: + break; + } + + if (target_mode != AV_KEEP) { + av_init = 1; + cm.avinput = target_mode; + 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(); + DisableAudioOutput(); + tvp_source_sel(target_input, target_format, cm.refclk); + cm.clkcnt = 0; //TODO: proper invalidate + strncpy(row1, avinput_str[cm.avinput], LCD_ROW_LEN+1); + strncpy(row2, " NO SYNC", LCD_ROW_LEN+1); + if (!menu_active) + lcd_write_status(); + } + + //usleep(MAINLOOP_SLEEP_US); + usleep(300); //avoid triggering multiple times per vsync + read_control(); + + if (av_init) { + status = get_status(target_input); + + switch (status) { + case ACTIVITY_CHANGE: + if (cm.sync_active) { + printf("Sync up\n"); + IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, (IORD_ALTERA_AVALON_PIO_DATA(PIO_0_BASE) | (1<<2))); //disable videogen + enable_outputs(); + } else { + printf("Sync lost\n"); + cm.clkcnt = 0; //TODO: proper invalidate + tvp_disable_output(); + //ths_source_sel(THS_STANDBY, 0); + strncpy(row1, avinput_str[cm.avinput], LCD_ROW_LEN+1); + strncpy(row2, " NO SYNC", LCD_ROW_LEN+1); + if (!menu_active) + lcd_write_status(); + } + break; + case MODE_CHANGE: + if (cm.sync_active) { + printf("Mode change\n"); + program_mode(); + } + break; + case INFO_CHANGE: + if (cm.sync_active) { + printf("Info change\n"); + set_videoinfo(); + } + break; + default: + break; + } + } + + btn_code_prev = btn_code; + remote_rpt_prev = remote_rpt; + } + + return 0; +} diff --git a/software/sys_controller/ossc/av_controller.c b/software/sys_controller/ossc/av_controller.c new file mode 100755 index 0000000..bad61a1 --- /dev/null +++ b/software/sys_controller/ossc/av_controller.c @@ -0,0 +1,419 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#include +#include +#include "system.h" +#include "string.h" +#include "altera_avalon_pio_regs.h" +#include "Altera_UP_SD_Card_Avalon_Interface_mod.h" +#include "altera_epcq_controller_mod.h" +#include "i2c_opencores.h" +#include "tvp7002.h" +#include "ths7353.h" +#include "video_modes.h" +#include "lcd.h" +#include "sysconfig.h" +#include "it6613.h" +#include "it6613_sys.h" +#include "HDMI_TX.h" +#include "hdmitx.h" +#include "ci_crc.h" +#include "cfg.h" +#include "av_controller.h" +#include "controls.h" +#include "memory.h" +#include "menu.h" + +#define LINECNT_THOLD 1 +#define STABLE_THOLD 1 +#define MIN_LINES_PROGRESSIVE 200 +#define MIN_LINES_INTERLACED 400 +#define SYNC_LOSS_THOLD 5 +#define STATUS_TIMEOUT 10000 + +extern alt_u16 rc_keymap[REMOTE_MAX_KEYS]; + +extern const alt_u32 clkrate[]; + +const char const *avinput_str[] = { "NO MODE", "AV1: RGBS", "AV1: RGsB", "AV2: YPbPr", "AV2: RGsB", "AV3: RGBHV", "AV3: RGBS", "AV3: RGsB" }; + +// Target configuration +avconfig_t tc; + +// Current mode +avmode_t cm; + +extern mode_data_t video_modes[]; +extern ypbpr_to_rgb_csc_t csc_coeffs[]; + +alt_u8 target_typemask; +alt_u8 target_type; +alt_u8 stable_frames; + +char row1[LCD_ROW_LEN+1], row2[LCD_ROW_LEN+1], menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; + + +short int sd_fw_handle; + +extern volatile alt_u8 menu_active; +extern volatile alt_u32 remote_code; +extern volatile alt_u8 remote_rpt, remote_rpt_prev; +extern volatile alt_u32 btn_code, btn_code_prev; + + +void TX_enable(tx_mode_t mode) +{ + //SetAVMute(TRUE); + DisableVideoOutput(); + EnableAVIInfoFrame(FALSE, NULL); + + EnableVideoOutput(PCLK_MEDIUM, COLOR_RGB444, COLOR_RGB444, mode == TX_HDMI); + if (!(IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & HDMITX_MODE_MASK) && mode == TX_HDMI) + HDMITX_SetAVIInfoFrame(HDMI_480p60, F_MODE_RGB444, 0, 0); + + // start Tx + SetAVMute(FALSE); +} + + +void set_lpf(alt_u8 lpf) +{ + alt_u32 pclk; + pclk = (clkrate[cm.refclk]/cm.clkcnt)*video_modes[cm.id].h_total; + printf("PCLK: %uHz\n", pclk); + + //Auto + if (lpf == 0) { + switch (target_type) { + case VIDEO_PC: + tvp_set_lpf((pclk < 30000000) ? 0x0F : 0); + ths_set_lpf(THS_LPF_BYPASS); + break; + case VIDEO_HDTV: + tvp_set_lpf(0); + ths_set_lpf(THS_LPF_BYPASS); + break; + case VIDEO_EDTV: + tvp_set_lpf(0); + ths_set_lpf(1); + break; + case VIDEO_SDTV: + case VIDEO_LDTV: + tvp_set_lpf(0); + ths_set_lpf(0); + break; + default: + break; + } + } else { + tvp_set_lpf((tc.video_lpf == 2) ? 0x0F : 0); + ths_set_lpf((tc.video_lpf > 2) ? (VIDEO_LPF_MAX-tc.video_lpf) : THS_LPF_BYPASS); + } +} + +// Check if input video status / target configuration has changed +status_t get_status(tvp_input_t input) +{ + alt_u32 data1, data2; + alt_u32 totlines, clkcnt; + alt_u8 progressive; + //alt_u8 refclk; + alt_u8 sync_active; + alt_u8 vsyncmode; + alt_u16 fpga_totlines; + status_t status; + static alt_u8 act_ctr; + alt_u32 ctr; + + status = NO_CHANGE; + + // Wait until vsync active (avoid noise coupled to I2C bus on earlier prototypes) + for (ctr=0; ctr> 16; + + // TVP7002 may randomly report "no sync" (especially with arcade boards), + // thus disable output only after N consecutive "no sync"-events + if (!cm.sync_active && sync_active) { + cm.sync_active = sync_active; + status = ACTIVITY_CHANGE; + act_ctr = 0; + } else if (cm.sync_active && !sync_active) { + printf("Sync down in %u...\n", SYNC_LOSS_THOLD-act_ctr); + if (act_ctr >= SYNC_LOSS_THOLD) { + act_ctr = 0; + cm.sync_active = sync_active; + status = ACTIVITY_CHANGE; + } else { + act_ctr++; + } + } else { + act_ctr = 0; + } + + + data1 = tvp_readreg(TVP_LINECNT1); + data2 = tvp_readreg(TVP_LINECNT2); + totlines = ((data2 & 0x0f) << 8) | data1; + progressive = !!(data2 & (1<<5)); + cm.macrovis = !!(data2 & (1<<6)); + + fpga_totlines = IORD_ALTERA_AVALON_PIO_DATA(PIO_4_BASE) & 0xffff; + + //TODO: check flags instead + if (vsyncmode == 0x2) { + progressive = 1; + } else if ((vsyncmode == 0x1) && fpga_totlines > ((totlines-1)*2)) { + progressive = 0; + totlines = fpga_totlines; //ugly hack + } + + data1 = tvp_readreg(TVP_CLKCNT1); + data2 = tvp_readreg(TVP_CLKCNT2); + clkcnt = ((data2 & 0x0f) << 8) | data1; + + if ((progressive && (totlines > MIN_LINES_PROGRESSIVE)) || (!progressive && (totlines > MIN_LINES_INTERLACED))) { + if ((abs((alt_16)totlines - (alt_16)cm.totlines) > LINECNT_THOLD) || (clkcnt != cm.clkcnt) || (progressive != cm.progressive)) { + printf("totlines: %u (cur) / %u (prev), clkcnt: %u (cur) / %u (prev). Data1: 0x%.2x, Data2: 0x%.2x\n", (unsigned)totlines, (unsigned)cm.totlines, (unsigned)clkcnt, (unsigned)cm.clkcnt, (unsigned)data1, (unsigned)data2); + stable_frames = 0; + } else if (stable_frames != STABLE_THOLD) { + stable_frames++; + if (stable_frames == STABLE_THOLD) + status = (status < MODE_CHANGE) ? MODE_CHANGE : status; + } + + + if ((tc.linemult_target != cm.cc.linemult_target) || + (tc.l3_mode != cm.cc.l3_mode) || + ((tc.s480p_mode != cm.cc.s480p_mode) && (video_modes[cm.id].flags & (MODE_DTV480P|MODE_VGA480P)))) + status = (status < MODE_CHANGE) ? MODE_CHANGE : status; + + + if (tc.disable_alc != cm.cc.disable_alc) + tvp_set_alc(tc.disable_alc, target_type); + + + cm.totlines = totlines; + cm.clkcnt = clkcnt; + cm.progressive = progressive; + } + + if ((tc.sl_mode != cm.cc.sl_mode) || + (tc.sl_str != cm.cc.sl_str) || + (tc.sl_id != cm.cc.sl_id) || + (tc.h_mask != cm.cc.h_mask) || + (tc.v_mask != cm.cc.v_mask)) + status = (status < INFO_CHANGE) ? INFO_CHANGE : status; + + if (tc.sampler_phase != cm.cc.sampler_phase) + tvp_set_hpll_phase(tc.sampler_phase-SAMPLER_PHASE_MIN); + + if (tc.sync_thold != cm.cc.sync_thold) + tvp_set_sog_thold(tc.sync_thold-SYNC_THOLD_MIN); + + if ((tc.pre_coast != cm.cc.pre_coast) || (tc.post_coast != cm.cc.post_coast)) + tvp_set_hpllcoast(tc.pre_coast, tc.post_coast); + + if (tc.ypbpr_cs != cm.cc.ypbpr_cs) + tvp_sel_csc(&csc_coeffs[tc.ypbpr_cs]); + + if (tc.video_lpf != cm.cc.video_lpf) + set_lpf(tc.video_lpf); + + if (tc.sync_lpf != cm.cc.sync_lpf) + tvp_set_sync_lpf(tc.sync_lpf); + + // use memcpy instead? + cm.cc = tc; + + return status; +} + +// h_info: [31:30] [29:28] [27:22] [21] [20:10] [7:0] +// | H_LINEMULT[1:0] | H_L3MODE[1:0] | H_MASK[5:0] | | H_ACTIVE[10:0] | H_BACKPORCH[7:0] | +// +// v_info: [31] [30] [29] [28:25] [24:19] [18] [17:7] [6] [5:0] +// | V_SCANLINES | V_SCANLINEDIR | V_SCANLINEID | V_SCANLINESTR[3:0] | V_MASK[5:0] | | V_ACTIVE[10:0] | | V_BACKPORCH[5:0] | +void set_videoinfo() +{ + alt_u8 slid_target; + + if (video_modes[cm.id].flags & MODE_L3ENABLE_MASK) { + cm.linemult = 2; + slid_target = cm.cc.sl_id ? 2 : 0; + } else if (video_modes[cm.id].flags & MODE_L2ENABLE) { + cm.linemult = 1; + slid_target = cm.cc.sl_id; + } else { + cm.linemult = 0; + slid_target = cm.cc.sl_id; + } + + IOWR_ALTERA_AVALON_PIO_DATA(PIO_2_BASE, (cm.linemult<<30) | (cm.cc.l3_mode<<28) | (cm.cc.h_mask)<<22 | (video_modes[cm.id].h_active<<10) | video_modes[cm.id].h_backporch); + IOWR_ALTERA_AVALON_PIO_DATA(PIO_3_BASE, ((!!cm.cc.sl_mode)<<31) | (cm.cc.sl_mode > 0 ? (cm.cc.sl_mode-1)<<30 : 0) | (slid_target<<19) | (cm.cc.sl_str<<25) | (cm.cc.v_mask<<19) | (video_modes[cm.id].v_active<<7) | video_modes[cm.id].v_backporch); +} + +// Configure TVP7002 and scan converter logic based on the video mode +void program_mode() +{ + alt_u32 data1, data2; + alt_u32 h_hz, v_hz_x100; + + // Mark as stable (needed after sync up to avoid unnecessary mode switch) + stable_frames = STABLE_THOLD; + + if ((cm.clkcnt != 0) && (cm.totlines != 0)) { //prevent div by 0 + h_hz = clkrate[cm.refclk]/cm.clkcnt; + v_hz_x100 = cm.progressive ? (100*clkrate[cm.refclk]/cm.clkcnt)/cm.totlines : (2*(100*clkrate[cm.refclk]/cm.clkcnt))/cm.totlines; + } else { + h_hz = 15700; + v_hz_x100 = 6000; + } + + 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)); + + data1 = tvp_readreg(TVP_HSINWIDTH); + data2 = tvp_readreg(TVP_VSINWIDTH); + printf("Hswidth: %u Vswidth: %u Macrovision: %u\n", (unsigned)data1, (unsigned)(data2 & 0x1F), (unsigned)cm.macrovis); + + //TODO: rewrite with strncpy to reduce code size + 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)); + //strncpy(row1, avinput_str[cm.avinput], LCD_ROW_LEN+1); + //strncpy(row2, avinput_str[cm.avinput], LCD_ROW_LEN+1); + if (!menu_active) + lcd_write_status(); + + //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, target_typemask, cm.cc.linemult_target, cm.cc.l3_mode, cm.cc.s480p_mode); + + if ( cm.id == -1) { + printf ("Error: no suitable mode found, defaulting to 240p\n"); + cm.id = 4; + } + + target_type = target_typemask & video_modes[cm.id].type; + + printf("Mode %s selected\n", video_modes[cm.id].name); + + tvp_source_setup(cm.id, target_type, cm.cc.disable_alc, (cm.progressive ? cm.totlines : cm.totlines/2), v_hz_x100/100, cm.refclk, cm.cc.pre_coast, cm.cc.post_coast); + set_lpf(cm.cc.video_lpf); + set_videoinfo(); +} + +// Initialize hardware +int init_hw() +{ + alt_u32 chiprev; + + // Reset error vector and scan converter + IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, 0x03); + IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, 0x00); + IOWR_ALTERA_AVALON_PIO_DATA(PIO_2_BASE, 0x00000000); + IOWR_ALTERA_AVALON_PIO_DATA(PIO_3_BASE, 0x00000000); + usleep(10000); + + // unreset hw + IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, 0x03); + + //wait >500ms for SD card interface to be stable + //over 200ms and LCD may be buggy? + usleep(200000); + + // IT6613 officially supports only 100kHz, but 400kHz seems to work + I2C_init(I2CA_BASE,ALT_CPU_FREQ,400000); + + + set_default_avconfig(); + // safe? + read_userdata(); + + /* Initialize the character display */ + lcd_init(); + + + if (!ths_init()) { + printf("Error: could not read from THS7353\n"); + return -2; + } + + /* check if TVP is found */ + chiprev = tvp_readreg(TVP_CHIPREV); + //printf("chiprev %d\n", chiprev); + + if ( chiprev == 0xff) { + printf("Error: could not read from TVP7002\n"); + return -3; + } + + tvp_init(); + + chiprev = HDMITX_ReadI2C_Byte(IT_DEVICEID); + + if ( chiprev != 0x13) { + printf("Error: could not read from IT6613\n"); + return -4; + } + + InitIT6613(); + + if (check_flash() != 0) { + printf("Error: incorrect flash type detected\n"); + return -1; + } + + // enforce DVI mode on non-DIY boards + if ((IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & HDMITX_MODE_MASK)) { + cm.cc.tx_mode = TX_DVI; + tc.tx_mode = TX_DVI; + } + + if (!(IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & PB1_BIT)) + setup_rc(); + + // init always is HDMI mode (fixes yellow screen bug) + TX_enable(TX_HDMI); + if (cm.cc.tx_mode) + TX_enable(cm.cc.tx_mode); + + SetAVMute(FALSE); + return 0; +} + +// Enable chip outputs +void enable_outputs() +{ + // program video mode + program_mode(); + // enable TVP output + tvp_enable_output(); + + // enable and unmute HDMITX + // TODO: check pclk + TX_enable(cm.cc.tx_mode); +} + diff --git a/software/sys_controller/ossc/av_controller.h b/software/sys_controller/ossc/av_controller.h new file mode 100644 index 0000000..2b22283 --- /dev/null +++ b/software/sys_controller/ossc/av_controller.h @@ -0,0 +1,91 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#ifndef AV_CONTROLLER_H_ +#define AV_CONTROLLER_H_ + +#include "altera_epcq_controller_mod.h" +#include "typedef.h" +#include "cfg.h" +#include "lcd.h" +#include "tvp7002.h" + +#define RC_MASK 0x0000ffff +#define PB_MASK 0x00030000 +#define PB0_BIT 0x00010000 +#define PB1_BIT 0x00020000 +#define HDMITX_MODE_MASK 0x00040000 + +extern char row1[LCD_ROW_LEN+1], row2[LCD_ROW_LEN+1], menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; + +#define lcd_write_menu() lcd_write((char*)&menu_row1, (char*)&menu_row2) +#define lcd_write_status() lcd_write((char*)&row1, (char*)&row2) + +// In reverse order of importance +typedef enum { + NO_CHANGE = 0, + INFO_CHANGE = 1, + MODE_CHANGE = 2, + TX_MODE_CHANGE = 3, + ACTIVITY_CHANGE = 4 +} status_t; + +typedef enum { + AV_KEEP = 0, + AV1_RGBs = 1, + AV1_RGsB = 2, + AV2_YPBPR = 3, + AV2_RGsB = 4, + AV3_RGBHV = 5, + AV3_RGBs = 6, + AV3_RGsB = 7 +} avinput_t; + +//TODO: transform binary values into flags +typedef struct { + alt_u32 totlines; + alt_u32 clkcnt; + alt_u8 progressive; + alt_u8 macrovis; + alt_u8 refclk; + alt_8 id; + alt_u8 sync_active; + alt_u8 linemult; + avinput_t avinput; + // Current configuration + avconfig_t cc; +} avmode_t; + +typedef enum { + TX_HDMI = 0, + TX_DVI = 1 +} tx_mode_t; + + +status_t get_status(tvp_input_t input); + +void TX_enable(tx_mode_t mode); + +void program_mode(void); +void set_videoinfo(void); + +int init_hw(void); +void enable_outputs(void); + +#endif /* AV_CONTROLLER_H_ */ diff --git a/software/sys_controller/ossc/cfg.c b/software/sys_controller/ossc/cfg.c new file mode 100644 index 0000000..49a555c --- /dev/null +++ b/software/sys_controller/ossc/cfg.c @@ -0,0 +1,39 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#include "string.h" +#include "cfg.h" +#include "av_controller.h" + + +// Target configuration +extern avconfig_t tc; + +// Current mode +extern avmode_t cm; + +void set_default_avconfig() +{ + memset(&cm.cc, 0, sizeof(avconfig_t)); + memset(&tc, 0, sizeof(avconfig_t)); + cm.cc.pre_coast = DEFAULT_PRE_COAST; + tc.pre_coast = DEFAULT_PRE_COAST; + cm.cc.post_coast = DEFAULT_POST_COAST; + tc.post_coast = DEFAULT_POST_COAST; +} diff --git a/software/sys_controller/ossc/cfg.h b/software/sys_controller/ossc/cfg.h new file mode 100644 index 0000000..6abd3cf --- /dev/null +++ b/software/sys_controller/ossc/cfg.h @@ -0,0 +1,66 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#ifndef CFG_H_ +#define CFG_H_ + +#include "altera_epcq_controller_mod.h" + +typedef struct { + alt_u8 sl_mode; + alt_u8 sl_str; + alt_u8 sl_id; + alt_u8 linemult_target; + alt_u8 l3_mode; + alt_u8 h_mask; + alt_u8 v_mask; + alt_u8 tx_mode; + alt_u8 s480p_mode; + alt_8 sampler_phase; + alt_u8 ypbpr_cs; + alt_8 sync_thold; + alt_u8 sync_lpf; + alt_u8 video_lpf; + alt_u8 pre_coast; + alt_u8 post_coast; + alt_u8 disable_alc; +} avconfig_t; + +#define MAINLOOP_SLEEP_US 10000 + +#define SCANLINESTR_MAX 15 +#define HV_MASK_MAX 63 +#define L3_MODE_MAX 3 +#define S480P_MODE_MAX 2 +#define SL_MODE_MAX 2 +#define SYNC_LPF_MAX 3 +#define VIDEO_LPF_MAX 5 +#define SAMPLER_PHASE_MIN -16 +#define SAMPLER_PHASE_MAX 15 +#define SYNC_THOLD_MIN -11 +#define SYNC_THOLD_MAX 20 +#define PLL_COAST_MIN 0 +#define PLL_COAST_MAX 5 + +#define DEFAULT_PRE_COAST 1 +#define DEFAULT_POST_COAST 0 + +void set_default_avconfig(void); + +#endif /* CFG_H_ */ diff --git a/software/sys_controller/ossc/controls.c b/software/sys_controller/ossc/controls.c new file mode 100644 index 0000000..f25ceb3 --- /dev/null +++ b/software/sys_controller/ossc/controls.c @@ -0,0 +1,126 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#include +#include "string.h" +#include "altera_avalon_pio_regs.h" +#include "altera_epcq_controller_mod.h" +#include "cfg.h" +#include "av_controller.h" +#include "lcd.h" +#include "video_modes.h" +#include "controls.h" +#include "menu.h" + +const char const *rc_keydesc[] = { "1", "2", "3", "MENU", "BACK", "UP", "DOWN", "LEFT", "RIGHT", "INFO", "LCD_BACKLIGHT", "HOTKEY1", "HOTKEY2", "HOTKEY3"}; + +volatile alt_u8 remote_rpt, remote_rpt_prev; +volatile alt_u32 btn_code, btn_code_prev; + +volatile alt_u16 rc_keymap[REMOTE_MAX_KEYS] = {0x3E29, 0x3EA9, 0x3E69, 0x3E4D, 0x3EED, 0x3E2D, 0x3ECD, 0x3EAD, 0x3E6D, 0x3E65, 0x3E01, 0x3EC1, 0x3E41, 0x3EA1}; +extern char menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; +volatile alt_u32 remote_code; + +alt_u8 menu_active; +extern volatile avconfig_t tc; +extern volatile avmode_t cm; + +extern mode_data_t video_modes[]; + +void setup_rc() +{ + int i, confirm; + alt_u32 remote_code_prev = 0xFFFF; + + for (i=0; i> 16) & 0x3); + lcd_write_menu(); + printf("Mod: %s\n", video_modes[cm.id].name); + printf("Lines: %u M: %u\n", IORD_ALTERA_AVALON_PIO_DATA(PIO_4_BASE) & 0xffff, cm.macrovis); + } else if (remote_code == rc_keymap[RC_LCDBL]) { + IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, (IORD_ALTERA_AVALON_PIO_DATA(PIO_0_BASE) ^ (1<<1))); + } else if (remote_code == rc_keymap[RC_HOTKEY1]) { + //tc.sl_mode = (tc.sl_mode > 0) ? 0 : 1; + tc.sl_mode = tc.sl_mode < SL_MODE_MAX ? tc.sl_mode+1 : 0; + } else if (remote_code == rc_keymap[RC_HOTKEY2]) { + //if (tc.sl_str > 0) + // tc.sl_str--; + tc.sl_str = tc.sl_str ? tc.sl_str-1 : SCANLINESTR_MAX; + } else if (remote_code == rc_keymap[RC_HOTKEY3]) { + //if (tc.sl_str < SCANLINESTR_MAX) + // tc.sl_str++; + tc.sl_str = tc.sl_str < SCANLINESTR_MAX ? tc.sl_str+1 : 0; + } + + if (btn_code_prev == 0) { + if (btn_code & PB1_BIT) + tc.sl_mode = (tc.sl_mode > 0) ? 0 : 1; + } + + if (menu_active) + display_menu(0); +} diff --git a/software/sys_controller/ossc/controls.h b/software/sys_controller/ossc/controls.h new file mode 100644 index 0000000..e52df18 --- /dev/null +++ b/software/sys_controller/ossc/controls.h @@ -0,0 +1,46 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#ifndef CONTROL_H_ +#define CONTROL_H_ + +#define REMOTE_MAX_KEYS 14 + +typedef enum { + RC_BTN1 = 0, + RC_BTN2, + RC_BTN3, + RC_MENU, + RC_BACK, + RC_UP, + RC_DOWN, + RC_LEFT, + RC_RIGHT, + RC_INFO, + RC_LCDBL, + RC_HOTKEY1, + RC_HOTKEY2, + RC_HOTKEY3, +} rc_code_t; + + +void setup_rc(void); +void read_control(void); + +#endif /* CONTROL_H_ */ diff --git a/software/sys_controller/ossc/fw_version.h b/software/sys_controller/ossc/fw_version.h new file mode 100644 index 0000000..9154696 --- /dev/null +++ b/software/sys_controller/ossc/fw_version.h @@ -0,0 +1,28 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#ifndef FW_VERSION_H_ +#define FW_VERSION_H_ + +#define FW_VER_MAJOR 0 +#define FW_VER_MINOR 70 +#define FW_UPDATE_RETRIES 3 + + +#endif /* FW_VERSION_H_ */ diff --git a/software/sys_controller/ossc/memory.c b/software/sys_controller/ossc/memory.c new file mode 100644 index 0000000..7780f5e --- /dev/null +++ b/software/sys_controller/ossc/memory.c @@ -0,0 +1,436 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#include +#include +#include "system.h" +#include "string.h" +#include "altera_avalon_pio_regs.h" +#include "altera_epcq_controller_mod.h" +#include "Altera_UP_SD_Card_Avalon_Interface_mod.h" +#include "tvp7002.h" +#include "sysconfig.h" +#include "cfg.h" +#include "av_controller.h" +#include "lcd.h" +#include "ci_crc.h" +#include "memory.h" +#include "controls.h" +#include "fw_version.h" + + +extern alt_epcq_controller_dev epcq_controller_0; +alt_epcq_controller_dev *epcq_controller_dev; + +extern char row1[LCD_ROW_LEN+1], row2[LCD_ROW_LEN+1], menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; + +extern alt_u16 rc_keymap[REMOTE_MAX_KEYS]; + +// Target configuration +extern avconfig_t tc; + +// Current mode +extern avmode_t cm; + +alt_up_sd_card_dev *sdcard_dev; + +int check_flash() +{ + epcq_controller_dev = &epcq_controller_0; + + if ((epcq_controller_dev == NULL) || !(epcq_controller_dev->is_epcs && (epcq_controller_dev->page_size == PAGESIZE))) + return -1; + + //printf("Flash size in bytes: %d\nSector size: %d (%d pages)\nPage size: %d\n", epcq_controller_dev->size_in_bytes, epcq_controller_dev->sector_size, epcq_controller_dev->sector_size/epcq_controller_dev->page_size, epcq_controller_dev->page_size); + + return 0; +} + + + +int read_flash(alt_u32 offset, alt_u32 length, alt_u8 *dstbuf) +{ + int retval, i; + + retval = alt_epcq_controller_read(&epcq_controller_dev->dev, offset, dstbuf, length); + if (retval != 0) + return -1; + + for (i=0; i> 24; + + return 0; +} + +int write_flash_page(alt_u8 *pagedata, alt_u32 length, alt_u32 pagenum) +{ + int retval, i; + + if ((pagenum % PAGES_PER_SECTOR) == 0) { + printf("Erasing sector %u\n", (unsigned)(pagenum/PAGES_PER_SECTOR)); + retval = alt_epcq_controller_erase_block(&epcq_controller_dev->dev, pagenum*PAGESIZE); + + if (retval != 0) { + strncpy(menu_row1, "Flash erase", LCD_ROW_LEN+1); + sniprintf(menu_row1, LCD_ROW_LEN+1, "error %d", retval); + menu_row2[0] = '\0'; + printf("Flash erase error, sector %u\nRetval %d\n", (unsigned)(pagenum/PAGES_PER_SECTOR), retval); + return -200; + } + } + + // Bit-reverse bytes for flash + for (i=0; i> 24; + + retval = alt_epcq_controller_write_block(&epcq_controller_dev->dev, (pagenum/PAGES_PER_SECTOR)*PAGES_PER_SECTOR*PAGESIZE, pagenum*PAGESIZE, pagedata, length); + + if (retval != 0) { + strncpy(menu_row1, "Flash write", LCD_ROW_LEN+1); + strncpy(menu_row2, "error", LCD_ROW_LEN+1); + printf("Flash write error, page %u\nRetval %d\n", (unsigned)pagenum, retval); + return -201; + } + + return retval; +} + +int verify_flash(alt_u32 offset, alt_u32 length, alt_u32 golden_crc, alt_u8 *tmpbuf) +{ + alt_u32 crcval=0, i, bytes_to_read; + int retval; + + for (i=0; i 512)) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "Invalid read cmd"); + menu_row2[0] = '\0'; + return -1; + } + + if (!Read_Sector_Data((offset/SD_BUFFER_SIZE), 0)) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "SD read failure"); + menu_row2[0] = '\0'; + return -2; + } + + // Copy buffer to SW + for (i=0; ibase, i); + *((alt_u32*)(dstbuf+i)) = tmp; + } + + return 0; +} + +int check_sdcard(alt_u8 *databuf) +{ + sdcard_dev = alt_up_sd_card_open_dev(ALTERA_UP_SD_CARD_AVALON_INTERFACE_0_NAME); + + if ((sdcard_dev == NULL) || !alt_up_sd_card_is_Present()) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "No SD card det."); + menu_row2[0] = '\0'; + return 1; + } + + return read_sd_block(0, 512, databuf); +} + +int check_fw_header(alt_u8 *databuf, fw_hdr *hdr) +{ + alt_u32 crcval, tmp; + + strncpy(hdr->fw_key, (char*)databuf, 4); + if (strncmp(hdr->fw_key, "OSSC", 4)) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "Invalid image"); + menu_row2[0] = '\0'; + return 1; + } + + hdr->version_major = databuf[4]; + hdr->version_minor = databuf[5]; + strncpy(hdr->version_suffix, (char*)(databuf+6), 8); + hdr->version_suffix[7] = 0; + + memcpy(&tmp, databuf+14, 4); + hdr->hdr_len = ALT_CI_NIOS_CUSTOM_INSTR_ENDIANCONVERTER_0(tmp); + memcpy(&tmp, databuf+18, 4); + hdr->data_len = ALT_CI_NIOS_CUSTOM_INSTR_ENDIANCONVERTER_0(tmp); + memcpy(&tmp, databuf+22, 4); + hdr->data_crc = ALT_CI_NIOS_CUSTOM_INSTR_ENDIANCONVERTER_0(tmp); + // Always at bytes [508-511] + memcpy(&tmp, databuf+508, 4); + hdr->hdr_crc = ALT_CI_NIOS_CUSTOM_INSTR_ENDIANCONVERTER_0(tmp); + + if (hdr->hdr_len < 26 || hdr->hdr_len > 508) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "Invalid header"); + menu_row2[0] = '\0'; + return -1; + } + + crcval = crcCI(databuf, hdr->hdr_len, 1); + + if (crcval != hdr->hdr_crc) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "Invalid hdr CRC"); + menu_row2[0] = '\0'; + return -2; + } + + return 0; +} + +int check_fw_image(alt_u32 offset, alt_u32 size, alt_u32 golden_crc, alt_u8 *tmpbuf) +{ + alt_u32 crcval=0, i, bytes_to_read; + int retval; + + for (i=0; i PAGESIZE) { + retval = write_flash_page(databuf+PAGESIZE, (bytes_to_rw-PAGESIZE), (i/PAGESIZE)+1); + if (retval != 0) + goto failure; + } + } + + strncpy(menu_row1, "Verifying flash", LCD_ROW_LEN+1); + strncpy(menu_row2, "please wait...", LCD_ROW_LEN+1); + lcd_write_menu(); + retval = verify_flash(0, fw_header.data_len, fw_header.data_crc, databuf); + if (retval != 0) + goto failure; + + return 0; + + +failure: + lcd_write_menu(); + usleep(1000000); + + // Probable rw error, retry update + if ((retval <= -200) && (retries > 0)) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "Retrying update"); + retries--; + goto update_init; + } + + return -1; +} + +int write_userdata() +{ + alt_u8 databuf[PAGESIZE]; + int retval; + + strncpy((char*)databuf, "USRDATA", 8); + databuf[8] = FW_VER_MAJOR; + databuf[9] = FW_VER_MINOR; + databuf[10] = 2; + + retval = write_flash_page(databuf, USERDATA_HDR_SIZE, (USERDATA_OFFSET/PAGESIZE)); + if (retval != 0) { + return -1; + } + + databuf[0] = UDE_REMOTE_MAP; + databuf[1] = 4+sizeof(rc_keymap); + databuf[2] = databuf[3] = 0; //padding + memcpy(databuf+4, rc_keymap, sizeof(rc_keymap)); + + retval = write_flash_page(databuf, databuf[1], (USERDATA_OFFSET/PAGESIZE)+1); + if (retval != 0) { + return -1; + } + + databuf[0] = UDE_AVCONFIG; + databuf[1] = 4+sizeof(avconfig_t); + databuf[2] = databuf[3] = 0; //padding + memcpy(databuf+4, &tc, sizeof(avconfig_t)); + + retval = write_flash_page(databuf, databuf[1], (USERDATA_OFFSET/PAGESIZE)+2); + if (retval != 0) { + return -1; + } + + return 0; +} + +int read_userdata() +{ + int retval, i; + alt_u8 databuf[PAGESIZE]; + userdata_hdr udhdr; + userdata_entry udentry; + + retval = read_flash(USERDATA_OFFSET, USERDATA_HDR_SIZE, databuf); + if (retval != 0) { + printf("Flash read error\n"); + return -1; + } + + strncpy(udhdr.userdata_key, (char*)databuf, 8); + if (strncmp(udhdr.userdata_key, "USRDATA", 8)) { + printf("No userdata found on flash\n"); + return 1; + } + + udhdr.version_major = databuf[8]; + udhdr.version_minor = databuf[9]; + udhdr.num_entries = databuf[10]; + + //TODO: check version compatibility + printf("Userdata: v%u.%.2u, %u entries\n", udhdr.version_major, udhdr.version_minor, udhdr.num_entries); + + for (i=0; i +// +// 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 . +// + +#ifndef MEMORY_H_ +#define MEMORY_H_ + +#include + +#define USERDATA_HDR_SIZE 11 +typedef struct { + char userdata_key[8]; + alt_u8 version_major; + alt_u8 version_minor; + alt_u8 num_entries; +} userdata_hdr; + +#define USERDATA_ENTRY_HDR_SIZE 2 +typedef struct { + alt_u8 type; + alt_u8 entry_len; +} userdata_entry; + +typedef enum { + UDE_REMOTE_MAP = 0, + UDE_AVCONFIG, +} userdata_entry_type; + + +typedef struct { + char fw_key[4]; + alt_u8 version_major; + alt_u8 version_minor; + char version_suffix[8]; + alt_u32 hdr_len; + alt_u32 data_len; + alt_u32 data_crc; + alt_u32 hdr_crc; +} fw_hdr; + +// EPCS16 pagesize is 256 bytes +// Flash is split 50-50 to FW and userdata, 1MB each +#define PAGESIZE 256 +#define PAGES_PER_SECTOR 256 +#define USERDATA_OFFSET 0x100000 +#define USERDATA_MAX_SIZE 0x1000 //4KB should be enough + +// SD controller uses 512-byte chunks +#define SD_BUFFER_SIZE 512 + +int check_flash(void); +int read_flash(alt_u32 offset, alt_u32 length, alt_u8 *dstbuf); +int write_flash_page(alt_u8 *pagedata, alt_u32 length, alt_u32 pagenum); +int verify_flash(alt_u32 offset, alt_u32 length, alt_u32 golden_crc, alt_u8 *tmpbuf); + +int read_sd_block(alt_u32 offset, alt_u32 size, alt_u8 *dstbuf); +int check_sdcard(alt_u8 *databuf); + +int check_fw_header(alt_u8 *databuf, fw_hdr *hdr); +int check_fw_image(alt_u32 offset, alt_u32 size, alt_u32 golden_crc, alt_u8 *tmpbuf); +int fw_update(void); + +int write_userdata(void); +int read_userdata(void); + +#endif /* MEMORY_H_ */ diff --git a/software/sys_controller/ossc/menu.c b/software/sys_controller/ossc/menu.c new file mode 100644 index 0000000..1c419e4 --- /dev/null +++ b/software/sys_controller/ossc/menu.c @@ -0,0 +1,292 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#include +#include +#include "system.h" +#include "string.h" +#include "altera_avalon_pio_regs.h" +#include "altera_epcq_controller_mod.h" +#include "lcd.h" +#include "av_controller.h" +#include "controls.h" +#include "memory.h" +#include "menu.h" +#include "cfg.h" + + +typedef enum { + NO_ACTION = 0, + NEXT_PAGE = 1, + PREV_PAGE = 2, + VAL_PLUS = 3, + VAL_MINUS = 4, +} menucode_id; + + +typedef enum { + SCANLINE_MODE, + SCANLINE_STRENGTH, + SCANLINE_ID, + H_MASK, + V_MASK, + SAMPLER_480P, + SAMPLER_PHASE, + YPBPR_COLORSPACE, + SYNC_THOLD, + PRE_COAST, + POST_COAST, + SYNC_LPF, + VIDEO_LPF, + DISABLE_ALC, + LINETRIPLE_ENABLE, + LINETRIPLE_MODE, + TX_MODE, +#ifndef DEBUG + FW_UPDATE, +#endif + SAVE_CONFIG +} menuitem_id; + +typedef struct { + const menuitem_id id; + const char *desc; +} menuitem_t; + +const menuitem_t menu[] = { + { SCANLINE_MODE, "Scanlines" }, + { SCANLINE_STRENGTH, "Scanline str." }, + { SCANLINE_ID, "Scanline id" }, + { H_MASK, "Horizontal mask" }, + { V_MASK, "Vertical mask" }, + { SAMPLER_480P, "480p in sampler" }, + { SAMPLER_PHASE, "Sampling phase" }, + { YPBPR_COLORSPACE, "YPbPr in ColSpa" }, + { SYNC_THOLD, "Analog sync thld" }, + { PRE_COAST, "H-PLL Pre-Coast" }, + { POST_COAST, "H-PLL Post-Coast" }, + { SYNC_LPF, "Analog sync LPF" }, + { VIDEO_LPF, "Video LPF" }, + { DISABLE_ALC, "Auto Lev. Contr." }, + { LINETRIPLE_ENABLE, "240p/288p lineX3" }, + { LINETRIPLE_MODE, "Linetriple mode" }, + { TX_MODE, "TX mode" }, +#ifndef DEBUG + { FW_UPDATE, "Firmware update" }, +#endif + { SAVE_CONFIG, "Save settings" }, +}; + +#define MENUITEMS (sizeof(menu)/sizeof(menuitem_t)) + +const char const *l3_mode_desc[] = { "Generic 16:9", "Generic 4:3", "320x240 optim.", "256x240 optim." }; +const char const *s480p_desc[] = { "Auto", "DTV 480p", "VGA 640x480" }; +const char const *sl_mode_desc[] = { "Off", "Horizontal", "Vertical" }; +const char const *sync_lpf_desc[] = { "Off", "33MHz", "10MHz", "2.5MHz" }; +const char const *video_lpf_desc[] = { "Auto", "Off", "95MHz (HDTV II)", "35MHz (HDTV I)", "16MHz (EDTV)", "9MHz (SDTV)" }; + + +extern char row1[LCD_ROW_LEN+1], row2[LCD_ROW_LEN+1], menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; + +extern alt_u16 rc_keymap[REMOTE_MAX_KEYS]; +extern volatile alt_u32 remote_code; + +extern ypbpr_to_rgb_csc_t csc_coeffs[]; + + + +// Target configuration +extern avconfig_t tc; + +void display_menu(alt_u8 forcedisp) +{ + menucode_id code; + int retval; + static alt_u8 menu_page; + + if (remote_code == rc_keymap[RC_UP]) + code = PREV_PAGE; + else if (remote_code == rc_keymap[RC_DOWN]) + code = NEXT_PAGE; + else if (remote_code == rc_keymap[RC_RIGHT]) + code = VAL_PLUS; + else if (remote_code == rc_keymap[RC_LEFT]) + code = VAL_MINUS; + else + code = NO_ACTION; + + if (!forcedisp && (code == NO_ACTION)) + return; + + if (code == PREV_PAGE) + menu_page = (menu_page+MENUITEMS-1) % MENUITEMS; + else if (code == NEXT_PAGE) + menu_page = (menu_page+1) % MENUITEMS; + + strncpy(menu_row1, menu[menu_page].desc, LCD_ROW_LEN+1); + + switch (menu[menu_page].id) { + case SCANLINE_MODE: + if (code == VAL_MINUS) + tc.sl_mode = tc.sl_mode ? tc.sl_mode-1 : SL_MODE_MAX; + else if (code == VAL_PLUS) + tc.sl_mode = tc.sl_mode < SL_MODE_MAX ? tc.sl_mode+1 : 0; + strncpy(menu_row2, sl_mode_desc[tc.sl_mode], LCD_ROW_LEN+1); + break; + case SCANLINE_STRENGTH: + if (code == VAL_MINUS) + tc.sl_str = tc.sl_str ? tc.sl_str-1 : SCANLINESTR_MAX; + else if (code == VAL_PLUS) + tc.sl_str = tc.sl_str < SCANLINESTR_MAX ? tc.sl_str+1 : 0; + sniprintf(menu_row2, LCD_ROW_LEN+1, "%u%%", ((tc.sl_str+1)*625)/100); + break; + case SCANLINE_ID: + if ((code == VAL_MINUS) || (code == VAL_PLUS)) + tc.sl_id = !tc.sl_id; + sniprintf(menu_row2, LCD_ROW_LEN+1, tc.sl_id ? "Odd" : "Even"); + break; + case H_MASK: + if ((code == VAL_MINUS) && (tc.h_mask > 0)) + tc.h_mask--; + else if ((code == VAL_PLUS) && (tc.h_mask < HV_MASK_MAX)) + tc.h_mask++; + sniprintf(menu_row2, LCD_ROW_LEN+1, "%u pixels", tc.h_mask); + break; + case V_MASK: + if ((code == VAL_MINUS) && (tc.v_mask > 0)) + tc.v_mask--; + else if ((code == VAL_PLUS) && (tc.v_mask < HV_MASK_MAX)) + tc.v_mask++; + sniprintf(menu_row2, LCD_ROW_LEN+1, "%u pixels", tc.v_mask); + break; + case SAMPLER_480P: + if (code == VAL_MINUS) + tc.s480p_mode = tc.s480p_mode ? tc.s480p_mode-1 : S480P_MODE_MAX; + else if (code == VAL_PLUS) + tc.s480p_mode = tc.s480p_mode < S480P_MODE_MAX ? tc.s480p_mode+1 : 0; + strncpy(menu_row2, s480p_desc[tc.s480p_mode], LCD_ROW_LEN+1); + break; + case SAMPLER_PHASE: + if (code == VAL_MINUS) + tc.sampler_phase = tc.sampler_phase > SAMPLER_PHASE_MIN ? tc.sampler_phase-1 : SAMPLER_PHASE_MAX; + else if (code == VAL_PLUS) + tc.sampler_phase = tc.sampler_phase < SAMPLER_PHASE_MAX ? tc.sampler_phase+1 : SAMPLER_PHASE_MIN; + sniprintf(menu_row2, LCD_ROW_LEN+1, "%d deg", ((tc.sampler_phase-SAMPLER_PHASE_MIN)*1125)/100); + break; + case YPBPR_COLORSPACE: + if ((code == VAL_MINUS) || (code == VAL_PLUS)) + tc.ypbpr_cs = !tc.ypbpr_cs; + strncpy(menu_row2, csc_coeffs[tc.ypbpr_cs].name, LCD_ROW_LEN+1); + break; + case SYNC_THOLD: + if (code == VAL_MINUS) + tc.sync_thold = tc.sync_thold > SYNC_THOLD_MIN ? tc.sync_thold-1 : SYNC_THOLD_MAX; + else if (code == VAL_PLUS) + tc.sync_thold = tc.sync_thold < SYNC_THOLD_MAX ? tc.sync_thold+1 : SYNC_THOLD_MIN; + sniprintf(menu_row2, LCD_ROW_LEN+1, "%d mV", ((tc.sync_thold-SYNC_THOLD_MIN)*1127)/100); + break; + case PRE_COAST: + if (code == VAL_MINUS) + tc.pre_coast = tc.pre_coast > PLL_COAST_MIN ? tc.pre_coast-1 : PLL_COAST_MAX; + else if (code == VAL_PLUS) + tc.pre_coast = tc.pre_coast < PLL_COAST_MAX ? tc.pre_coast+1 : PLL_COAST_MIN; + sniprintf(menu_row2, LCD_ROW_LEN+1, "%u lines", tc.pre_coast); + break; + case POST_COAST: + if (code == VAL_MINUS) + tc.post_coast = tc.post_coast > PLL_COAST_MIN ? tc.post_coast-1 : PLL_COAST_MAX; + else if (code == VAL_PLUS) + tc.post_coast = tc.post_coast < PLL_COAST_MAX ? tc.post_coast+1 : PLL_COAST_MIN; + sniprintf(menu_row2, LCD_ROW_LEN+1, "%u lines", tc.post_coast); + break; + case SYNC_LPF: + if (code == VAL_MINUS) + tc.sync_lpf = tc.sync_lpf ? tc.sync_lpf-1 : SYNC_LPF_MAX; + else if (code == VAL_PLUS) + tc.sync_lpf = tc.sync_lpf < SYNC_LPF_MAX ? tc.sync_lpf+1 : 0; + strncpy(menu_row2, sync_lpf_desc[tc.sync_lpf], LCD_ROW_LEN+1); + break; + case VIDEO_LPF: + if (code == VAL_MINUS) + tc.video_lpf = tc.video_lpf ? tc.video_lpf-1 : VIDEO_LPF_MAX; + else if (code == VAL_PLUS) + tc.video_lpf = tc.video_lpf < VIDEO_LPF_MAX ? tc.video_lpf+1 : 0; + strncpy(menu_row2, video_lpf_desc[tc.video_lpf], LCD_ROW_LEN+1); + break; + case DISABLE_ALC: + if ((code == VAL_MINUS) || (code == VAL_PLUS)) + tc.disable_alc = !tc.disable_alc; + sniprintf(menu_row2, LCD_ROW_LEN+1, tc.disable_alc ? "Disabled" : "Enabled"); + break; + case LINETRIPLE_ENABLE: + if ((code == VAL_MINUS) || (code == VAL_PLUS)) + tc.linemult_target = !tc.linemult_target; + sniprintf(menu_row2, LCD_ROW_LEN+1, tc.linemult_target ? "On" : "Off"); + break; + case LINETRIPLE_MODE: + if (code == VAL_MINUS) + tc.l3_mode = tc.l3_mode ? tc.l3_mode-1 : L3_MODE_MAX; + else if (code == VAL_PLUS) + tc.l3_mode = tc.l3_mode < L3_MODE_MAX ? tc.l3_mode+1 : 0; + strncpy(menu_row2, l3_mode_desc[tc.l3_mode], LCD_ROW_LEN+1); + break; + case TX_MODE: + if (!(IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & HDMITX_MODE_MASK) && ((code == VAL_MINUS) || (code == VAL_PLUS))) { + tc.tx_mode = !tc.tx_mode; + TX_enable(tc.tx_mode); + } + sniprintf(menu_row2, LCD_ROW_LEN+1, tc.tx_mode ? "DVI" : "HDMI"); + break; +#ifndef DEBUG + case FW_UPDATE: + if ((code == VAL_MINUS) || (code == VAL_PLUS)) { + retval = fw_update(); + if (retval == 0) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "Fw update OK"); + sniprintf(menu_row2, LCD_ROW_LEN+1, "Please restart"); + } else { + sniprintf(menu_row1, LCD_ROW_LEN+1, "FW not"); + sniprintf(menu_row2, LCD_ROW_LEN+1, "updated"); + } + } else { + sniprintf(menu_row2, LCD_ROW_LEN+1, "press <- or ->"); + } + break; +#endif + case SAVE_CONFIG: + if ((code == VAL_MINUS) || (code == VAL_PLUS)) { + retval = write_userdata(); + if (retval == 0) { + sniprintf(menu_row2, LCD_ROW_LEN+1, "Done"); + } else { + sniprintf(menu_row2, LCD_ROW_LEN+1, "error"); + } + } else { + sniprintf(menu_row2, LCD_ROW_LEN+1, "press <- or ->"); + } + break; + default: + sniprintf(menu_row2, LCD_ROW_LEN+1, "MISSING ITEM"); + break; + } + + lcd_write_menu(); + + return; +} diff --git a/software/sys_controller/ossc/menu.h b/software/sys_controller/ossc/menu.h new file mode 100644 index 0000000..233c4a3 --- /dev/null +++ b/software/sys_controller/ossc/menu.h @@ -0,0 +1,25 @@ +// +// Copyright (C) 2015-2016 Markus Hiienkari +// +// 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 . +// + +#ifndef MENU_H_ +#define MENU_H_ + +void display_menu(alt_u8 forcedisp); + +#endif /* MENU_H_ */ diff --git a/software/sys_controller/tvp7002/tvp7002.c b/software/sys_controller/tvp7002/tvp7002.c index 0a2b156..52bd18e 100755 --- a/software/sys_controller/tvp7002/tvp7002.c +++ b/software/sys_controller/tvp7002/tvp7002.c @@ -38,6 +38,11 @@ const ypbpr_to_rgb_csc_t csc_coeffs[] = { { "Rec. 709", 0x2000, 0x0000, 0x323E, 0x2000, 0xFA04, 0xF113, 0x2000, 0x3B61, 0x0000 }, // eq. 105 }; +const alt_u8 Kvco[] = {75, 85, 150, 200}; +const char const *Kvco_str[] = { "Ultra low", "Low", "Medium", "High" }; + +const alt_u32 clkrate[] = {27000000, 6500000}; //in MHz + extern mode_data_t video_modes[]; static inline void tvp_set_ssthold(alt_u8 vsdetect_thold) @@ -111,7 +116,7 @@ void tvp_set_alc(alt_u8 disable_alc, video_type type) } -inline alt_u32 tvp_readreg(alt_u32 regaddr) +alt_u32 tvp_readreg(alt_u32 regaddr) { I2C_start(I2CA_BASE, TVP_BASE, 0); I2C_write(I2CA_BASE, regaddr, 1); //don't use repeated start as it seems unreliable at 400kHz @@ -119,14 +124,14 @@ inline alt_u32 tvp_readreg(alt_u32 regaddr) return I2C_read(I2CA_BASE,1); } -inline void tvp_writereg(alt_u32 regaddr, alt_u8 data) +void tvp_writereg(alt_u32 regaddr, alt_u8 data) { I2C_start(I2CA_BASE, TVP_BASE, 0); I2C_write(I2CA_BASE, regaddr, 0); I2C_write(I2CA_BASE, data, 1); } -inline void tvp_reset() +void tvp_reset() { usleep(10000); IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, 0x00); @@ -135,7 +140,7 @@ inline void tvp_reset() usleep(10000); } -inline void tvp_disable_output() +void tvp_disable_output() { usleep(10000); tvp_writereg(TVP_MISCCTRL1, 0x13); @@ -144,7 +149,7 @@ inline void tvp_disable_output() usleep(10000); } -inline void tvp_enable_output() +void tvp_enable_output() { usleep(10000); tvp_writereg(TVP_MISCCTRL1, 0x11); @@ -153,7 +158,7 @@ inline void tvp_enable_output() usleep(10000); } -inline void tvp_set_hpllcoast(alt_u8 pre, alt_u8 post) +void tvp_set_hpllcoast(alt_u8 pre, alt_u8 post) { tvp_writereg(TVP_HPLLPRECOAST, pre); tvp_writereg(TVP_HPLLPOSTCOAST, post); diff --git a/software/sys_controller/tvp7002/tvp7002.h b/software/sys_controller/tvp7002/tvp7002.h index af2f7d6..f54c1ce 100755 --- a/software/sys_controller/tvp7002/tvp7002.h +++ b/software/sys_controller/tvp7002/tvp7002.h @@ -33,9 +33,6 @@ typedef enum { TVP_INPUT3 = 2 } tvp_input_t; -static const alt_u8 Kvco[] = {75, 85, 150, 200}; -static const char *Kvco_str[] = { "Ultra low", "Low", "Medium", "High" }; - typedef enum { REFCLK_EXT27 = 0, REFCLK_INTCLK = 1 @@ -54,21 +51,20 @@ typedef struct { alt_u16 B_Pr; } ypbpr_to_rgb_csc_t; -static const alt_u32 clkrate[] = {27000000, 6500000}; //in MHz void tvp_set_alc(alt_u8 disable_alc, video_type type); -inline alt_u32 tvp_readreg(alt_u32 regaddr); +alt_u32 tvp_readreg(alt_u32 regaddr); -inline void tvp_writereg(alt_u32 regaddr, alt_u8 data); +void tvp_writereg(alt_u32 regaddr, alt_u8 data); -inline void tvp_reset(); +void tvp_reset(); -inline void tvp_disable_output(); +void tvp_disable_output(); -inline void tvp_enable_output(); +void tvp_enable_output(); -inline void tvp_set_hpllcoast(alt_u8 pre, alt_u8 post); +void tvp_set_hpllcoast(alt_u8 pre, alt_u8 post); void tvp_init();